C++/CX exposes `IPropertyValue` through `Platform::Details::CreateValue`, which returns a `Platform::Object` (which just seems to be a `IPropertyValue` object + C++ RTTI) containing the boxed value.
Apps don't seem to call `CreateValue` directly with a typecode. The code for boxing values gets generated when a value type gets assigned to a `Platform::Object` variable, as documented [here.](https://learn.microsoft.com/en-us/cpp/extensions/boxing-cpp-component-extens...) The generated code will:
1. Call `__abi_make_type_id` with a `struct __abi_type_descriptor *` value, which is just a typecode + string pair. This returns a `Platform::Type` object. 2. Call `Platform::Type::GetTypeCode` on the returned `Platform::Type` object to get back the typecode. 3. Call `Platform::Details::CreateValue` with the typecode and a pointer to the actual value that needs to be boxed.
Apart from the usual WinRT methods, `Platform::Type` obejcts also impement the `IEquatable` and `IPrintable` interfaces. I don't know what their vtables look like, though.
The `Platform::Type` and `Platform::Object` classes also have associated RTTI (can be demonstrated by calling `__RTtypeid`), which we'll also need to emit at some point in the future.
-- v4: vccorlib140: Use the correct symbol name for InitControlBlock on i386 and arm. vccorlib140: Implement Platform::Details::CreateValue. vccorlib140: Add stub for Platform::Details::CreateValue.
From: Vibhav Pant vibhavp@gmail.com
--- dlls/vccorlib140/tests/Makefile.in | 2 +- dlls/vccorlib140/tests/vccorlib.c | 165 +++++++++++++++++++++++++++++ dlls/vccorlib140/vccorlib.c | 48 +++++++++ dlls/vccorlib140/vccorlib140.spec | 22 ++-- 4 files changed, 225 insertions(+), 12 deletions(-)
diff --git a/dlls/vccorlib140/tests/Makefile.in b/dlls/vccorlib140/tests/Makefile.in index b75d820bc8c..9d20ff64424 100644 --- a/dlls/vccorlib140/tests/Makefile.in +++ b/dlls/vccorlib140/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = vccorlib140.dll -IMPORTS = ole32 uuid +IMPORTS = combase ole32 uuid
SOURCES = \ vccorlib.c diff --git a/dlls/vccorlib140/tests/vccorlib.c b/dlls/vccorlib140/tests/vccorlib.c index 199481ff779..bef246f2760 100644 --- a/dlls/vccorlib140/tests/vccorlib.c +++ b/dlls/vccorlib140/tests/vccorlib.c @@ -27,6 +27,9 @@ #include "activation.h" #include "objbase.h" #include "weakreference.h" +#define WIDL_using_Windows_Foundation +#include "windows.foundation.h" +#include "winstring.h" #include "wine/test.h"
#define DEFINE_EXPECT(func) \ @@ -103,6 +106,12 @@ DEFINE_EXPECT(PostInitialize); DEFINE_EXPECT(PreUninitialize); DEFINE_EXPECT(PostUninitialize);
+struct __abi_type_descriptor +{ + const WCHAR *name; + int type_id; +}; + static HRESULT (__cdecl *pInitializeData)(int); static void (__cdecl *pUninitializeData)(int); static HRESULT (WINAPI *pGetActivationFactoryByPCWSTR)(const WCHAR *, const GUID *, void **); @@ -111,6 +120,11 @@ static void *(__cdecl *pAllocate)(size_t); static void (__cdecl *pFree)(void *); static void *(__cdecl *pAllocateWithWeakRef)(ptrdiff_t, size_t); static void (__thiscall *pReleaseTarget)(void *); +static void *(WINAPI *p___abi_make_type_id)(const struct __abi_type_descriptor *desc); +static bool (__cdecl *p_platform_type_Equals_Object)(void *, void *); +static int (__cdecl *p_platform_type_GetTypeCode)(void *); +static HSTRING (__cdecl *p_platform_type_ToString)(void *); +static HSTRING (__cdecl *p_platform_type_get_FullName)(void *);
static BOOL init(void) { @@ -137,6 +151,13 @@ static BOOL init(void) pFree = (void *)GetProcAddress(hmod, "?Free@Heap@Details@Platform@@SAXPAX@Z"); pAllocateWithWeakRef = (void *)GetProcAddress(hmod, "?Allocate@Heap@Details@Platform@@SAPAXII@Z"); pReleaseTarget = (void *)GetProcAddress(hmod, "?ReleaseTarget@ControlBlock@Details@Platform@@AAAXXZ"); + p___abi_make_type_id = (void *)GetProcAddress(hmod, + "?__abi_make_type_id@@YAP$AAVType@Platform@@ABU__abi_type_descriptor@@@Z"); + p_platform_type_Equals_Object = (void *)GetProcAddress(hmod, "?Equals@Type@Platform@@U$AAA_NP$AAVObject@2@@Z"); + p_platform_type_GetTypeCode = (void *)GetProcAddress(hmod, + "?GetTypeCode@Type@Platform@@SA?AW4TypeCode@2@P$AAV12@@Z"); + p_platform_type_ToString = (void *)GetProcAddress(hmod, "?ToString@Type@Platform@@U$AAAP$AAVString@2@XZ"); + p_platform_type_get_FullName = (void *)GetProcAddress(hmod, "?get@FullName@Type@Platform@@Q$AAAP$AAVString@3@XZ"); #else if (sizeof(void *) == 8) { @@ -147,6 +168,15 @@ static BOOL init(void) pFree = (void *)GetProcAddress(hmod, "?Free@Heap@Details@Platform@@SAXPEAX@Z"); pAllocateWithWeakRef = (void *)GetProcAddress(hmod, "?Allocate@Heap@Details@Platform@@SAPEAX_K0@Z"); pReleaseTarget = (void *)GetProcAddress(hmod, "?ReleaseTarget@ControlBlock@Details@Platform@@AEAAXXZ"); + p___abi_make_type_id = (void *)GetProcAddress(hmod, + "?__abi_make_type_id@@YAPE$AAVType@Platform@@AEBU__abi_type_descriptor@@@Z"); + p_platform_type_Equals_Object = (void *)GetProcAddress(hmod, + "?Equals@Type@Platform@@UE$AAA_NPE$AAVObject@2@@Z"); + p_platform_type_GetTypeCode = (void *)GetProcAddress(hmod, + "?GetTypeCode@Type@Platform@@SA?AW4TypeCode@2@PE$AAV12@@Z"); + p_platform_type_ToString = (void *)GetProcAddress(hmod, "?ToString@Type@Platform@@UE$AAAPE$AAVString@2@XZ"); + p_platform_type_get_FullName = (void *)GetProcAddress(hmod, + "?get@FullName@Type@Platform@@QE$AAAPE$AAVString@3@XZ"); } else { @@ -157,6 +187,14 @@ static BOOL init(void) pFree = (void *)GetProcAddress(hmod, "?Free@Heap@Details@Platform@@SAXPAX@Z"); pAllocateWithWeakRef = (void *)GetProcAddress(hmod, "?Allocate@Heap@Details@Platform@@SAPAXII@Z"); pReleaseTarget = (void *)GetProcAddress(hmod, "?ReleaseTarget@ControlBlock@Details@Platform@@AAEXXZ"); + p___abi_make_type_id = (void *)GetProcAddress(hmod, + "?__abi_make_type_id@@YGP$AAVType@Platform@@ABU__abi_type_descriptor@@@Z"); + p_platform_type_Equals_Object = (void *)GetProcAddress(hmod, "?Equals@Type@Platform@@U$AAA_NP$AAVObject@2@@Z"); + p_platform_type_GetTypeCode = (void *)GetProcAddress(hmod, + "?GetTypeCode@Type@Platform@@SA?AW4TypeCode@2@P$AAV12@@Z"); + p_platform_type_ToString = (void *)GetProcAddress(hmod, "?ToString@Type@Platform@@U$AAAP$AAVString@2@XZ"); + p_platform_type_get_FullName = (void *)GetProcAddress(hmod, + "?get@FullName@Type@Platform@@Q$AAAP$AAVString@3@XZ"); } #endif ok(pGetActivationFactoryByPCWSTR != NULL, "GetActivationFactoryByPCWSTR not available\n"); @@ -165,6 +203,11 @@ static BOOL init(void) ok(pFree != NULL, "Free not available\n"); ok(pAllocateWithWeakRef != NULL, "AllocateWithWeakRef not available\n"); ok(pReleaseTarget != NULL, "ReleaseTarget not available\n"); + ok(p___abi_make_type_id != NULL, "__abi_make_type_id not available\n"); + ok(p_platform_type_Equals_Object != NULL, "Platform::Type::Equals not available\n"); + ok(p_platform_type_GetTypeCode != NULL, "Platform::Type::GetTypeCode not available\n"); + ok(p_platform_type_ToString != NULL, "Platform::Type::ToString not available\n"); + ok(p_platform_type_get_FullName != NULL, "Platform::Type::FullName not available\n");
init_thiscall_thunk();
@@ -610,6 +653,127 @@ static void test_AllocateWithWeakRef(void) ok(count == 0, "got count %lu\n", count); }
+#define check_interface(o, i) check_interface_(__LINE__, (o), (i)) +static void check_interface_(int line, void *obj, const GUID *iid) +{ + HRESULT hr; + void *out; + + hr = IUnknown_QueryInterface((IUnknown *)obj, iid, &out); + ok_(__FILE__, line)(hr == S_OK, "got hr %#lx\n", hr); + if (SUCCEEDED(hr)) IUnknown_Release((IUnknown *)out); +} + +/* Additional interfaces implemented by Platform::Object. */ +DEFINE_GUID(IID_IEquatable,0xde0cbaec,0xe077,0x4e92,0x84,0xbe,0xc6,0xd4,0x8d,0xca,0x30,0x06); +DEFINE_GUID(IID_IPrintable,0xde0cbaeb,0x8065,0x4a45,0x96,0xb1,0xc9,0xd4,0x43,0xf9,0xba,0xb3); + +static void test___abi_make_type_id(void) +{ + const struct __abi_type_descriptor desc = {L"foo", 0xdeadbeef}, desc2 = {L"foo", 0xdeadbeef}, desc3 = {NULL, 1}; + void *type_obj, *type_obj2; + const WCHAR *buf; + int typecode; + HSTRING str; + ULONG count; + bool equals; + HRESULT hr; + + type_obj = p___abi_make_type_id(&desc); + todo_wine ok(type_obj != NULL, "got type_obj %p\n", type_obj); + if (!type_obj) + { + skip("__abi_make_type_id failed\n"); + return; + } + + todo_wine check_interface(type_obj, &IID_IInspectable); + todo_wine check_interface(type_obj, &IID_IClosable); + todo_wine check_interface(type_obj, &IID_IMarshal); + todo_wine check_interface(type_obj, &IID_IAgileObject); + todo_wine check_interface(type_obj, &IID_IEquatable); + todo_wine check_interface(type_obj, &IID_IPrintable); + + hr = IInspectable_GetRuntimeClassName(type_obj, &str); + ok(hr == S_OK, "got hr %#lx\n", hr); + buf = WindowsGetStringRawBuffer(str, NULL); + todo_wine ok(buf && !wcscmp(buf, L"Platform.Type"), "got buf %s\n", debugstr_w(buf)); + WindowsDeleteString(str); + + equals = p_platform_type_Equals_Object(type_obj, type_obj); + todo_wine ok(equals, "got equals %d\n", equals); + equals = p_platform_type_Equals_Object(type_obj, NULL); + todo_wine ok(!equals, "got equals %d\n", equals); + + typecode = p_platform_type_GetTypeCode(type_obj); + todo_wine ok(typecode == 0xdeadbeef, "got typecode %d\n", typecode); + + str = p_platform_type_ToString(type_obj); + buf = WindowsGetStringRawBuffer(str, NULL); + todo_wine ok(buf && !wcscmp(buf, L"foo"), "got buf %s\n", debugstr_w(buf)); + WindowsDeleteString(str); + + str = p_platform_type_get_FullName(type_obj); + todo_wine ok(str != NULL, "got str %p\n", str); + buf = WindowsGetStringRawBuffer(str, NULL); + todo_wine ok(buf && !wcscmp(buf, L"foo"), "got buf %s != %s\n", debugstr_w(buf), debugstr_w(L"foo")); + WindowsDeleteString(str); + + type_obj2 = p___abi_make_type_id(&desc); + todo_wine ok(type_obj2 != NULL, "got type_obj %p\n", type_obj); + ok(type_obj2 != type_obj, "got type_obj2 %p\n", type_obj2); + + todo_wine check_interface(type_obj2, &IID_IInspectable); + todo_wine check_interface(type_obj2, &IID_IClosable); + todo_wine check_interface(type_obj2, &IID_IMarshal); + todo_wine check_interface(type_obj2, &IID_IAgileObject); + todo_wine check_interface(type_obj2, &IID_IEquatable); + todo_wine check_interface(type_obj2, &IID_IPrintable); + + equals = p_platform_type_Equals_Object(type_obj2, type_obj); + todo_wine ok(equals, "got equals %d\n", equals); + + count = IInspectable_Release(type_obj); + ok(count == 0, "got count %lu\n", count); + + equals = p_platform_type_Equals_Object(NULL, NULL); + todo_wine ok(equals, "got equals %d\n", equals); + + type_obj = p___abi_make_type_id(&desc2); + todo_wine ok(type_obj != NULL, "got type_obj %p\n", type_obj); + + /* Platform::Type::Equals only seems to compare the value of the __abi_type_descriptor pointer. */ + equals = p_platform_type_Equals_Object(type_obj, type_obj2); + todo_wine ok(!equals, "got equals %d\n", equals); + + count = IInspectable_Release(type_obj); + ok(count == 0, "got count %lu\n", count); + + type_obj = p___abi_make_type_id(&desc3); + todo_wine ok(type_obj != NULL, "got type_obj %p\n", type_obj); + + equals = p_platform_type_Equals_Object(type_obj, type_obj2); + todo_wine ok(!equals, "got equals %d\n", equals); + + typecode = p_platform_type_GetTypeCode(type_obj); + todo_wine ok(typecode == 1, "got typecode %d\n", typecode); + + str = p_platform_type_ToString(type_obj); + ok(str == NULL, "got str %s\n", debugstr_hstring(str)); + + str = p_platform_type_get_FullName(type_obj); + ok(str == NULL, "got str %s\n", debugstr_hstring(str)); + + count = IInspectable_Release(type_obj); + ok(count == 0, "got count %lu\n", count); + + count = IInspectable_Release(type_obj2); + ok(count == 0, "got count %lu\n", count); + + typecode = p_platform_type_GetTypeCode(NULL); + ok(typecode == 0, "got typecode %d\n", typecode); +} + START_TEST(vccorlib) { if(!init()) @@ -621,4 +785,5 @@ START_TEST(vccorlib) test_Allocate(); test_AllocateWithWeakRef_inline(); test_AllocateWithWeakRef(); + test___abi_make_type_id(); } diff --git a/dlls/vccorlib140/vccorlib.c b/dlls/vccorlib140/vccorlib.c index e225e7ce5a7..9cccd2533d6 100644 --- a/dlls/vccorlib140/vccorlib.c +++ b/dlls/vccorlib140/vccorlib.c @@ -225,3 +225,51 @@ void __thiscall control_block_ReleaseTarget(struct control_block *weakref) if ((object = InterlockedCompareExchangePointer((void *)&weakref->object, NULL, weakref->object))) Free(object); } + +struct __abi_type_descriptor +{ + const WCHAR *name; + int type_id; +}; + +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) +{ + FIXME("(%s) stub\n", debugstr_abi_type_descriptor(desc)); + + return NULL; +} + +bool __cdecl platform_type_Equals_Object(void *this, void *object) +{ + FIXME("(%p, %p) stub\n", this, object); + + return false; +} + +int __cdecl platform_type_GetTypeCode(void *this) +{ + FIXME("(%p) stub\n", this); + + return 0; +} + +HSTRING __cdecl platform_type_ToString(void *this) +{ + FIXME("(%p) stub\n", this); + + return NULL; +} + +HSTRING __cdecl platform_type_get_FullName(void *type) +{ + FIXME("(%p) stub\n", type); + + return NULL; +} diff --git a/dlls/vccorlib140/vccorlib140.spec b/dlls/vccorlib140/vccorlib140.spec index 8ff8b9b09fc..97f2b4d3cc7 100644 --- a/dlls/vccorlib140/vccorlib140.spec +++ b/dlls/vccorlib140/vccorlib140.spec @@ -12,8 +12,8 @@ @ stub -arch=win64 ?Equals@OnePhaseConstructedAttribute@CompilerServices@Runtime@Platform@@QE$AAA_NPE$AAVObject@4@@Z @ stub -arch=win32 ?Equals@STAThreadAttribute@Platform@@Q$AAA_NP$AAVObject@2@@Z @ stub -arch=win64 ?Equals@STAThreadAttribute@Platform@@QE$AAA_NPE$AAVObject@2@@Z -@ stub -arch=win32 ?Equals@Type@Platform@@U$AAA_NP$AAVObject@2@@Z -@ stub -arch=win64 ?Equals@Type@Platform@@UE$AAA_NPE$AAVObject@2@@Z +@ cdecl -arch=win32 ?Equals@Type@Platform@@U$AAA_NP$AAVObject@2@@Z(ptr ptr) platform_type_Equals_Object +@ cdecl -arch=win64 ?Equals@Type@Platform@@UE$AAA_NPE$AAVObject@2@@Z(ptr ptr) platform_type_Equals_Object @ stub -arch=win32 ?Equals@ValueType@Platform@@Q$AAA_NP$AAVObject@2@@Z @ stub -arch=win64 ?Equals@ValueType@Platform@@QE$AAA_NPE$AAVObject@2@@Z @ stub -arch=win32 ?Equals@char16@default@@QAA_NP$AAVObject@Platform@@@Z @@ -177,8 +177,8 @@ @ stub -arch=win64 ?GetType@uint64@default@@QEAAPE$AAVType@Platform@@XZ @ stub -arch=win32 ?GetType@uint8@default@@QAAP$AAVType@Platform@@XZ @ stub -arch=win64 ?GetType@uint8@default@@QEAAPE$AAVType@Platform@@XZ -@ stub -arch=win32 ?GetTypeCode@Type@Platform@@SA?AW4TypeCode@2@P$AAV12@@Z -@ stub -arch=win64 ?GetTypeCode@Type@Platform@@SA?AW4TypeCode@2@PE$AAV12@@Z +@ cdecl -arch=win32 ?GetTypeCode@Type@Platform@@SA?AW4TypeCode@2@P$AAV12@@Z(ptr) platform_type_GetTypeCode +@ cdecl -arch=win64 ?GetTypeCode@Type@Platform@@SA?AW4TypeCode@2@PE$AAV12@@Z(ptr) platform_type_GetTypeCode @ stub -arch=i386 ?GetWeakReference@Details@Platform@@YGPAU__abi_IUnknown@@Q$ADVObject@2@@Z @ stub -arch=arm ?GetWeakReference@Details@Platform@@YAPAU__abi_IUnknown@@Q$ADVObject@2@@Z @ stub -arch=win64 ?GetWeakReference@Details@Platform@@YAPEAU__abi_IUnknown@@QE$ADVObject@2@@Z @@ -246,8 +246,8 @@ @ stub -arch=win64 ?<Dispose>@String@Platform@@UE$AAAXXZ @ stub -arch=win32 ??0FailureException@Platform@@Q$AAA@P$AAVString@1@@Z @ stub -arch=win64 ??0FailureException@Platform@@QE$AAA@PE$AAVString@1@@Z -@ stub -arch=win32 ?ToString@Type@Platform@@U$AAAP$AAVString@2@XZ -@ stub -arch=win64 ?ToString@Type@Platform@@UE$AAAPE$AAVString@2@XZ +@ cdecl -arch=win32 ?ToString@Type@Platform@@U$AAAP$AAVString@2@XZ(ptr) platform_type_ToString +@ cdecl -arch=win64 ?ToString@Type@Platform@@UE$AAAPE$AAVString@2@XZ(ptr) platform_type_ToString @ stub -arch=win32 ?ToString@ValueType@Platform@@Q$AAAP$AAVString@2@XZ @ stub -arch=win64 ?ToString@ValueType@Platform@@QE$AAAPE$AAVString@2@XZ @ stub -arch=win32 ?ToString@char16@default@@QAAP$AAVString@Platform@@XZ @@ -347,9 +347,9 @@ @ stub -arch=i386 ?__abi_cast_String_to_Object@__abi_details@@YGP$AAVObject@Platform@@P$AAVString@3@@Z @ stub -arch=arm ?__abi_cast_String_to_Object@__abi_details@@YAP$AAVObject@Platform@@P$AAVString@3@@Z @ stub -arch=win64 ?__abi_cast_String_to_Object@__abi_details@@YAPE$AAVObject@Platform@@PE$AAVString@3@@Z -@ stub -arch=i386 ?__abi_make_type_id@@YGP$AAVType@Platform@@ABU__abi_type_descriptor@@@Z -@ stub -arch=arm ?__abi_make_type_id@@YAP$AAVType@Platform@@ABU__abi_type_descriptor@@@Z -@ stub -arch=win64 ?__abi_make_type_id@@YAPE$AAVType@Platform@@AEBU__abi_type_descriptor@@@Z +@ stdcall -arch=i386 ?__abi_make_type_id@@YGP$AAVType@Platform@@ABU__abi_type_descriptor@@@Z(ptr) __abi_make_type_id +@ stdcall -arch=arm ?__abi_make_type_id@@YAP$AAVType@Platform@@ABU__abi_type_descriptor@@@Z(ptr) __abi_make_type_id +@ stdcall -arch=win64 ?__abi_make_type_id@@YAPE$AAVType@Platform@@AEBU__abi_type_descriptor@@@Z(ptr) __abi_make_type_id @ stub -arch=win32 ??0IntPtr@Platform@@QAA@PAX@Z @ stub -arch=win64 ??0IntPtr@Platform@@QEAA@PEAX@Z @ stub -arch=i386 ?__abi_translateCurrentException@@YGJ_N@Z @@ -365,8 +365,8 @@ @ stub ?get@CurrentAllocationId@Heap@Details@Platform@@SAHXZ @ stub ?get@Empty@Rect@Foundation@Windows@@SA?AV234@XZ @ stub ?get@Empty@Size@Foundation@Windows@@SA?AV234@XZ -@ stub -arch=win32 ?get@FullName@Type@Platform@@Q$AAAP$AAVString@3@XZ -@ stub -arch=win64 ?get@FullName@Type@Platform@@QE$AAAPE$AAVString@3@XZ +@ cdecl -arch=win32 ?get@FullName@Type@Platform@@Q$AAAP$AAVString@3@XZ(ptr) platform_type_get_FullName +@ cdecl -arch=win64 ?get@FullName@Type@Platform@@QE$AAAPE$AAVString@3@XZ(ptr) platform_type_get_FullName @ stub -arch=win32 ?get@HasInverse@Matrix3D@Media3D@Media@Xaml@UI@Windows@@QAA_NXZ @ stub -arch=win64 ?get@HasInverse@Matrix3D@Media3D@Media@Xaml@UI@Windows@@QEAA_NXZ @ stub -arch=win32 ??0InvalidArgumentException@Platform@@Q$AAA@P$AAVString@1@@Z
From: Vibhav Pant vibhavp@gmail.com
--- dlls/vccorlib140/tests/vccorlib.c | 32 ++++---- dlls/vccorlib140/vccorlib.c | 120 +++++++++++++++++++++++++++++- 2 files changed, 134 insertions(+), 18 deletions(-)
diff --git a/dlls/vccorlib140/tests/vccorlib.c b/dlls/vccorlib140/tests/vccorlib.c index bef246f2760..cafe95faf77 100644 --- a/dlls/vccorlib140/tests/vccorlib.c +++ b/dlls/vccorlib140/tests/vccorlib.c @@ -680,30 +680,30 @@ static void test___abi_make_type_id(void) HRESULT hr;
type_obj = p___abi_make_type_id(&desc); - todo_wine ok(type_obj != NULL, "got type_obj %p\n", type_obj); + ok(type_obj != NULL, "got type_obj %p\n", type_obj); if (!type_obj) { skip("__abi_make_type_id failed\n"); return; }
- todo_wine check_interface(type_obj, &IID_IInspectable); - todo_wine check_interface(type_obj, &IID_IClosable); - todo_wine check_interface(type_obj, &IID_IMarshal); - todo_wine check_interface(type_obj, &IID_IAgileObject); + check_interface(type_obj, &IID_IInspectable); + check_interface(type_obj, &IID_IClosable); + check_interface(type_obj, &IID_IMarshal); + check_interface(type_obj, &IID_IAgileObject); todo_wine check_interface(type_obj, &IID_IEquatable); todo_wine check_interface(type_obj, &IID_IPrintable);
hr = IInspectable_GetRuntimeClassName(type_obj, &str); ok(hr == S_OK, "got hr %#lx\n", hr); buf = WindowsGetStringRawBuffer(str, NULL); - todo_wine ok(buf && !wcscmp(buf, L"Platform.Type"), "got buf %s\n", debugstr_w(buf)); + ok(buf && !wcscmp(buf, L"Platform.Type"), "got buf %s\n", debugstr_w(buf)); WindowsDeleteString(str);
equals = p_platform_type_Equals_Object(type_obj, type_obj); todo_wine ok(equals, "got equals %d\n", equals); equals = p_platform_type_Equals_Object(type_obj, NULL); - todo_wine ok(!equals, "got equals %d\n", equals); + ok(!equals, "got equals %d\n", equals);
typecode = p_platform_type_GetTypeCode(type_obj); todo_wine ok(typecode == 0xdeadbeef, "got typecode %d\n", typecode); @@ -720,13 +720,13 @@ static void test___abi_make_type_id(void) WindowsDeleteString(str);
type_obj2 = p___abi_make_type_id(&desc); - todo_wine ok(type_obj2 != NULL, "got type_obj %p\n", type_obj); + ok(type_obj2 != NULL, "got type_obj %p\n", type_obj); ok(type_obj2 != type_obj, "got type_obj2 %p\n", type_obj2);
- todo_wine check_interface(type_obj2, &IID_IInspectable); - todo_wine check_interface(type_obj2, &IID_IClosable); - todo_wine check_interface(type_obj2, &IID_IMarshal); - todo_wine check_interface(type_obj2, &IID_IAgileObject); + check_interface(type_obj2, &IID_IInspectable); + check_interface(type_obj2, &IID_IClosable); + check_interface(type_obj2, &IID_IMarshal); + check_interface(type_obj2, &IID_IAgileObject); todo_wine check_interface(type_obj2, &IID_IEquatable); todo_wine check_interface(type_obj2, &IID_IPrintable);
@@ -740,20 +740,20 @@ static void test___abi_make_type_id(void) todo_wine ok(equals, "got equals %d\n", equals);
type_obj = p___abi_make_type_id(&desc2); - todo_wine ok(type_obj != NULL, "got type_obj %p\n", type_obj); + ok(type_obj != NULL, "got type_obj %p\n", type_obj);
/* Platform::Type::Equals only seems to compare the value of the __abi_type_descriptor pointer. */ equals = p_platform_type_Equals_Object(type_obj, type_obj2); - todo_wine ok(!equals, "got equals %d\n", equals); + ok(!equals, "got equals %d\n", equals);
count = IInspectable_Release(type_obj); ok(count == 0, "got count %lu\n", count);
type_obj = p___abi_make_type_id(&desc3); - todo_wine ok(type_obj != NULL, "got type_obj %p\n", type_obj); + ok(type_obj != NULL, "got type_obj %p\n", type_obj);
equals = p_platform_type_Equals_Object(type_obj, type_obj2); - todo_wine ok(!equals, "got equals %d\n", equals); + ok(!equals, "got equals %d\n", equals);
typecode = p_platform_type_GetTypeCode(type_obj); todo_wine ok(typecode == 1, "got typecode %d\n", typecode); diff --git a/dlls/vccorlib140/vccorlib.c b/dlls/vccorlib140/vccorlib.c index 9cccd2533d6..27ccdfe178c 100644 --- a/dlls/vccorlib140/vccorlib.c +++ b/dlls/vccorlib140/vccorlib.c @@ -25,6 +25,8 @@ #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"
@@ -232,6 +234,102 @@ struct __abi_type_descriptor 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_vtbl = +{ + /* IUnknown */ + platform_type_QueryInterface, + platform_type_AddRef, + platform_type_Release, + platform_type_GetIids, + platform_type_GetRuntimeClassName, + platform_type_GetTrustLevel, + platform_type_Close, + +}; + static const char *debugstr_abi_type_descriptor(const struct __abi_type_descriptor *desc) { if (!desc) return "(null)"; @@ -241,9 +339,27 @@ static const char *debugstr_abi_type_descriptor(const struct __abi_type_descript
void *WINAPI __abi_make_type_id(const struct __abi_type_descriptor *desc) { - FIXME("(%s) stub\n", debugstr_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;
- return NULL; + TRACE("(%s)\n", debugstr_abi_type_descriptor(desc)); + + obj = Allocate(sizeof(*obj)); + obj->IClosable_iface.lpVtbl = &platform_type_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(void *this, void *object)
From: Vibhav Pant vibhavp@gmail.com
--- dlls/vccorlib140/tests/vccorlib.c | 19 ++++++++----------- dlls/vccorlib140/vccorlib.c | 31 +++++++++++++++++++------------ 2 files changed, 27 insertions(+), 23 deletions(-)
diff --git a/dlls/vccorlib140/tests/vccorlib.c b/dlls/vccorlib140/tests/vccorlib.c index cafe95faf77..2f32eee36d2 100644 --- a/dlls/vccorlib140/tests/vccorlib.c +++ b/dlls/vccorlib140/tests/vccorlib.c @@ -701,22 +701,22 @@ static void test___abi_make_type_id(void) WindowsDeleteString(str);
equals = p_platform_type_Equals_Object(type_obj, type_obj); - todo_wine ok(equals, "got equals %d\n", equals); + ok(equals, "got equals %d\n", equals); equals = p_platform_type_Equals_Object(type_obj, NULL); ok(!equals, "got equals %d\n", equals);
typecode = p_platform_type_GetTypeCode(type_obj); - todo_wine ok(typecode == 0xdeadbeef, "got typecode %d\n", typecode); + ok(typecode == 0xdeadbeef, "got typecode %d\n", typecode);
str = p_platform_type_ToString(type_obj); buf = WindowsGetStringRawBuffer(str, NULL); - todo_wine ok(buf && !wcscmp(buf, L"foo"), "got buf %s\n", debugstr_w(buf)); + ok(buf && !wcscmp(buf, L"foo"), "got buf %s\n", debugstr_w(buf)); WindowsDeleteString(str);
str = p_platform_type_get_FullName(type_obj); - todo_wine ok(str != NULL, "got str %p\n", str); + ok(str != NULL, "got str %p\n", str); buf = WindowsGetStringRawBuffer(str, NULL); - todo_wine ok(buf && !wcscmp(buf, L"foo"), "got buf %s != %s\n", debugstr_w(buf), debugstr_w(L"foo")); + ok(buf && !wcscmp(buf, L"foo"), "got buf %s != %s\n", debugstr_w(buf), debugstr_w(L"foo")); WindowsDeleteString(str);
type_obj2 = p___abi_make_type_id(&desc); @@ -731,13 +731,13 @@ static void test___abi_make_type_id(void) todo_wine check_interface(type_obj2, &IID_IPrintable);
equals = p_platform_type_Equals_Object(type_obj2, type_obj); - todo_wine ok(equals, "got equals %d\n", equals); + ok(equals, "got equals %d\n", equals);
count = IInspectable_Release(type_obj); ok(count == 0, "got count %lu\n", count);
equals = p_platform_type_Equals_Object(NULL, NULL); - todo_wine ok(equals, "got equals %d\n", equals); + ok(equals, "got equals %d\n", equals);
type_obj = p___abi_make_type_id(&desc2); ok(type_obj != NULL, "got type_obj %p\n", type_obj); @@ -756,7 +756,7 @@ static void test___abi_make_type_id(void) ok(!equals, "got equals %d\n", equals);
typecode = p_platform_type_GetTypeCode(type_obj); - todo_wine ok(typecode == 1, "got typecode %d\n", typecode); + ok(typecode == 1, "got typecode %d\n", typecode);
str = p_platform_type_ToString(type_obj); ok(str == NULL, "got str %s\n", debugstr_hstring(str)); @@ -769,9 +769,6 @@ static void test___abi_make_type_id(void)
count = IInspectable_Release(type_obj2); ok(count == 0, "got count %lu\n", count); - - typecode = p_platform_type_GetTypeCode(NULL); - ok(typecode == 0, "got typecode %d\n", typecode); }
START_TEST(vccorlib) diff --git a/dlls/vccorlib140/vccorlib.c b/dlls/vccorlib140/vccorlib.c index 27ccdfe178c..ff4cbf12b20 100644 --- a/dlls/vccorlib140/vccorlib.c +++ b/dlls/vccorlib140/vccorlib.c @@ -362,30 +362,37 @@ void *WINAPI __abi_make_type_id(const struct __abi_type_descriptor *desc) return &obj->IClosable_iface; }
-bool __cdecl platform_type_Equals_Object(void *this, void *object) +bool __cdecl platform_type_Equals_Object(struct platform_type *this, struct platform_type *object) { - FIXME("(%p, %p) stub\n", this, object); + TRACE("(%p, %p)\n", this, object);
- return false; + return this == object || (this && object && this->desc == object->desc); }
-int __cdecl platform_type_GetTypeCode(void *this) +int __cdecl platform_type_GetTypeCode(struct platform_type *this) { - FIXME("(%p) stub\n", this); + TRACE("(%p)\n", this);
- return 0; + return this->desc->type_id; }
-HSTRING __cdecl platform_type_ToString(void *this) +HSTRING __cdecl platform_type_ToString(struct platform_type *this) { - FIXME("(%p) stub\n", this); + HSTRING str = NULL; + HRESULT hr; + + TRACE("(%p)\n", this);
- return NULL; + /* 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(void *type) +HSTRING __cdecl platform_type_get_FullName(struct platform_type *type) { - FIXME("(%p) stub\n", type); + TRACE("(%p)\n", type);
- return NULL; + return platform_type_ToString(type); }
From: Vibhav Pant vibhavp@gmail.com
--- dlls/vccorlib140/tests/vccorlib.c | 194 ++++++++++++++++++++++++++++++ dlls/vccorlib140/vccorlib.c | 7 ++ dlls/vccorlib140/vccorlib140.spec | 6 +- 3 files changed, 204 insertions(+), 3 deletions(-)
diff --git a/dlls/vccorlib140/tests/vccorlib.c b/dlls/vccorlib140/tests/vccorlib.c index 2f32eee36d2..1a409ce51ab 100644 --- a/dlls/vccorlib140/tests/vccorlib.c +++ b/dlls/vccorlib140/tests/vccorlib.c @@ -125,6 +125,7 @@ static bool (__cdecl *p_platform_type_Equals_Object)(void *, void *); static int (__cdecl *p_platform_type_GetTypeCode)(void *); static HSTRING (__cdecl *p_platform_type_ToString)(void *); static HSTRING (__cdecl *p_platform_type_get_FullName)(void *); +static void *(WINAPI *pCreateValue)(int type, const void *);
static BOOL init(void) { @@ -158,6 +159,7 @@ static BOOL init(void) "?GetTypeCode@Type@Platform@@SA?AW4TypeCode@2@P$AAV12@@Z"); p_platform_type_ToString = (void *)GetProcAddress(hmod, "?ToString@Type@Platform@@U$AAAP$AAVString@2@XZ"); p_platform_type_get_FullName = (void *)GetProcAddress(hmod, "?get@FullName@Type@Platform@@Q$AAAP$AAVString@3@XZ"); + pCreateValue = (void *)GetProcAddress(hmod, "?CreateValue@Details@Platform@@YAP$AAVObject@2@W4TypeCode@2@PBX@Z"); #else if (sizeof(void *) == 8) { @@ -177,6 +179,8 @@ static BOOL init(void) p_platform_type_ToString = (void *)GetProcAddress(hmod, "?ToString@Type@Platform@@UE$AAAPE$AAVString@2@XZ"); p_platform_type_get_FullName = (void *)GetProcAddress(hmod, "?get@FullName@Type@Platform@@QE$AAAPE$AAVString@3@XZ"); + pCreateValue = (void *)GetProcAddress(hmod, + "?CreateValue@Details@Platform@@YAPE$AAVObject@2@W4TypeCode@2@PEBX@Z"); } else { @@ -195,6 +199,8 @@ static BOOL init(void) p_platform_type_ToString = (void *)GetProcAddress(hmod, "?ToString@Type@Platform@@U$AAAP$AAVString@2@XZ"); p_platform_type_get_FullName = (void *)GetProcAddress(hmod, "?get@FullName@Type@Platform@@Q$AAAP$AAVString@3@XZ"); + pCreateValue = (void *)GetProcAddress(hmod, + "?CreateValue@Details@Platform@@YGP$AAVObject@2@W4TypeCode@2@PBX@Z"); } #endif ok(pGetActivationFactoryByPCWSTR != NULL, "GetActivationFactoryByPCWSTR not available\n"); @@ -208,6 +214,7 @@ static BOOL init(void) ok(p_platform_type_GetTypeCode != NULL, "Platform::Type::GetTypeCode not available\n"); ok(p_platform_type_ToString != NULL, "Platform::Type::ToString not available\n"); ok(p_platform_type_get_FullName != NULL, "Platform::Type::FullName not available\n"); + ok(pCreateValue != NULL, "CreateValue not available\n");
init_thiscall_thunk();
@@ -771,6 +778,192 @@ static void test___abi_make_type_id(void) ok(count == 0, "got count %lu\n", count); }
+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 void test_CreateValue(void) +{ + union value { + UINT8 uint8; + UINT16 uint16; + UINT32 uint32; + UINT64 uint64; + FLOAT single; + DOUBLE dbl; + boolean boolean; + GUID guid; + DateTime time; + TimeSpan span; + Point point; + Size size; + Rect rect; + }; + static const struct { + int typecode; + union value value; + PropertyType exp_winrt_type; + } test_cases[] = { + {TYPECODE_BOOLEAN, {.boolean = true}, PropertyType_Boolean}, + {TYPECODE_CHAR16, {.uint16 = 0xbeef}, PropertyType_Char16}, + {TYPECODE_UINT8, {.uint8 = 0xbe}, PropertyType_UInt8}, + {TYPECODE_INT16, {.uint16 = 0xbeef}, PropertyType_Int16}, + {TYPECODE_UINT16, {.uint16 = 0xbeef}, PropertyType_UInt16}, + {TYPECODE_INT32, {.uint32 = 0xdeadbeef}, PropertyType_Int32}, + {TYPECODE_UINT32, {.uint32 = 0xdeadbeef}, PropertyType_UInt32}, + {TYPECODE_INT64, {.uint64 = 0xdeadbeefdeadbeef}, PropertyType_Int64}, + {TYPECODE_UINT64, {.uint64 = 0xdeadbeefdeadbeef}, PropertyType_UInt64}, + {TYPECODE_SINGLE, {.single = 2.71828}, PropertyType_Single}, + {TYPECODE_DOUBLE, {.dbl = 2.7182818284}, PropertyType_Double}, + {TYPECODE_DATETIME, {.time = {0xdeadbeefdeadbeef}}, PropertyType_DateTime}, + {TYPECODE_TIMESPAN, {.span = {0xdeadbeefdeadbeef}}, PropertyType_TimeSpan}, + {TYPECODE_POINT, {.point = {2.71828, 3.14159}}, PropertyType_Point}, + {TYPECODE_SIZE, {.size = {2.71828, 3.14159}}, PropertyType_Size}, + {TYPECODE_RECT, {.rect = {2.71828, 3.14159, 23.140692, 0.20787}}, PropertyType_Rect}, + {TYPECODE_GUID, {.guid = IID_IInspectable}, PropertyType_Guid}, + }; + static const int null_typecodes[] = {0, 1, 2, 5,15, 17}; + PropertyType type; + const WCHAR *buf; + ULONG count, i; + HSTRING str; + HRESULT hr; + void *obj; + + hr = pInitializeData(1); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + for (i = 0; i < ARRAY_SIZE(test_cases); i++) + { + union value value = {0}; + type = PropertyType_Empty; + + winetest_push_context("test_cases[%lu]", i); + + obj = pCreateValue(test_cases[i].typecode, &test_cases[i].value); + todo_wine ok(obj != NULL, "got value %p\n", obj); + if (!obj) continue; + + check_interface(obj, &IID_IInspectable); + check_interface(obj, &IID_IPropertyValue); + + hr = IPropertyValue_get_Type(obj, &type); + ok(hr == S_OK, "got hr %#lx\n", hr); + ok(type == test_cases[i].exp_winrt_type, "got type %d != %d\n", type, test_cases[i].exp_winrt_type); + + switch (test_cases[i].exp_winrt_type) + { + case PropertyType_Boolean: + hr = IPropertyValue_GetBoolean(obj, &value.boolean); + break; + case PropertyType_Char16: + hr = IPropertyValue_GetChar16(obj, &value.uint16); + break; + case PropertyType_UInt8: + hr = IPropertyValue_GetUInt8(obj, &value.uint8); + break; + case PropertyType_Int16: + hr = IPropertyValue_GetInt16(obj, (INT16 *)&value.uint16); + break; + case PropertyType_UInt16: + hr = IPropertyValue_GetUInt16(obj, &value.uint16); + break; + case PropertyType_Int32: + hr = IPropertyValue_GetInt32(obj, (INT32 *)&value.uint32); + break; + case PropertyType_UInt32: + hr = IPropertyValue_GetUInt32(obj, &value.uint32); + break; + case PropertyType_Int64: + hr = IPropertyValue_GetInt64(obj, (INT64 *)&value.uint64); + break; + case PropertyType_UInt64: + hr = IPropertyValue_GetUInt64(obj, &value.uint64); + break; + case PropertyType_Single: + hr = IPropertyValue_GetSingle(obj, &value.single); + break; + case PropertyType_Double: + hr = IPropertyValue_GetDouble(obj, &value.dbl); + break; + case PropertyType_DateTime: + hr = IPropertyValue_GetDateTime(obj, &value.time); + break; + case PropertyType_TimeSpan: + hr = IPropertyValue_GetTimeSpan(obj, &value.span); + break; + case PropertyType_Point: + hr = IPropertyValue_GetPoint(obj, &value.point); + break; + case PropertyType_Size: + hr = IPropertyValue_GetSize(obj, &value.size); + break; + case PropertyType_Rect: + hr = IPropertyValue_GetRect(obj, &value.rect); + break; + case PropertyType_Guid: + hr = IPropertyValue_GetGuid(obj, &value.guid); + break; + DEFAULT_UNREACHABLE; + } + + ok(hr == S_OK, "got hr %#lx\n", hr); + ok(!memcmp(&test_cases[i].value, &value, sizeof(value)), "got unexpected value\n"); + count = IPropertyValue_Release(obj); + ok(count == 0, "got count %lu\n", count); + + winetest_pop_context(); + } + + hr = WindowsCreateString(L"foo", 3, &str); + ok(hr == S_OK, "got hr %#lx\n", hr); + obj = pCreateValue(TYPECODE_STRING, &str); + WindowsDeleteString(str); + todo_wine ok(broken(obj != NULL), "got obj %p\n", obj); /* Returns NULL on i386 Windows 10. */ + if (obj) + { + type = PropertyType_Empty; + hr = IPropertyValue_get_Type(obj, &type); + ok(hr == S_OK, "got hr %#lx\n", hr); + ok(type == PropertyType_String, "got type %d\n", type); + str = NULL; + hr = IPropertyValue_GetString(obj, &str); + ok(hr == S_OK, "got hr %#lx\n", hr); + ok(str != NULL, "got str %p\n", str); + buf = WindowsGetStringRawBuffer(str, NULL); + ok(buf && !wcscmp(buf, L"foo"), "got buf %s\n", debugstr_w(buf)); + WindowsDeleteString(str); + count = IPropertyValue_Release(obj); + ok(count == 0, "got count %lu\n", count); + } + + for (i = 0; i < ARRAY_SIZE(null_typecodes); i++) + { + obj = pCreateValue(null_typecodes[i], &i); + ok(obj == NULL, "got obj %p\n", obj); + } + + pUninitializeData(0); +} + START_TEST(vccorlib) { if(!init()) @@ -783,4 +976,5 @@ START_TEST(vccorlib) test_AllocateWithWeakRef_inline(); test_AllocateWithWeakRef(); test___abi_make_type_id(); + test_CreateValue(); } diff --git a/dlls/vccorlib140/vccorlib.c b/dlls/vccorlib140/vccorlib.c index ff4cbf12b20..c6c0139cd9b 100644 --- a/dlls/vccorlib140/vccorlib.c +++ b/dlls/vccorlib140/vccorlib.c @@ -396,3 +396,10 @@ HSTRING __cdecl platform_type_get_FullName(struct platform_type *type)
return platform_type_ToString(type); } + +void *WINAPI CreateValue(int typecode, const void *val) +{ + FIXME("(%d, %p) stub\n", typecode, val); + + return NULL; +} diff --git a/dlls/vccorlib140/vccorlib140.spec b/dlls/vccorlib140/vccorlib140.spec index 97f2b4d3cc7..faecd3b8519 100644 --- a/dlls/vccorlib140/vccorlib140.spec +++ b/dlls/vccorlib140/vccorlib140.spec @@ -519,9 +519,9 @@ @ stub -arch=win64 ?CreateException@Exception@Platform@@SAPE$AAV12@H@Z @ stub -arch=win32 ?CreateException@Exception@Platform@@SAP$AAV12@HP$AAVString@2@@Z @ stub -arch=win64 ?CreateException@Exception@Platform@@SAPE$AAV12@HPE$AAVString@2@@Z -@ stub -arch=i386 ?CreateValue@Details@Platform@@YGP$AAVObject@2@W4TypeCode@2@PBX@Z -@ stub -arch=arm ?CreateValue@Details@Platform@@YAP$AAVObject@2@W4TypeCode@2@PBX@Z -@ stub -arch=win64 ?CreateValue@Details@Platform@@YAPE$AAVObject@2@W4TypeCode@2@PEBX@Z +@ stdcall -arch=i386 ?CreateValue@Details@Platform@@YGP$AAVObject@2@W4TypeCode@2@PBX@Z(long ptr) CreateValue +@ stdcall -arch=arm ?CreateValue@Details@Platform@@YAP$AAVObject@2@W4TypeCode@2@PBX@Z(long ptr) CreateValue +@ stdcall -arch=win64 ?CreateValue@Details@Platform@@YAPE$AAVObject@2@W4TypeCode@2@PEBX@Z(long ptr) CreateValue @ stub ?EnableFactoryCache@@YAXXZ @ stub -arch=win32 ?EnumerateAllocatedObjects@Heap@Details@Platform@@SAXP$AAVHeapEntryHandler@23@@Z @ stub -arch=win64 ?EnumerateAllocatedObjects@Heap@Details@Platform@@SAXPE$AAVHeapEntryHandler@23@@Z
From: Vibhav Pant vibhavp@gmail.com
--- dlls/vccorlib140/tests/vccorlib.c | 5 +- dlls/vccorlib140/vccorlib.c | 130 +++++++++++++++++++++++++++++- 2 files changed, 130 insertions(+), 5 deletions(-)
diff --git a/dlls/vccorlib140/tests/vccorlib.c b/dlls/vccorlib140/tests/vccorlib.c index 1a409ce51ab..21a5afe42a2 100644 --- a/dlls/vccorlib140/tests/vccorlib.c +++ b/dlls/vccorlib140/tests/vccorlib.c @@ -859,8 +859,7 @@ static void test_CreateValue(void) winetest_push_context("test_cases[%lu]", i);
obj = pCreateValue(test_cases[i].typecode, &test_cases[i].value); - todo_wine ok(obj != NULL, "got value %p\n", obj); - if (!obj) continue; + ok(obj != NULL, "got value %p\n", obj);
check_interface(obj, &IID_IInspectable); check_interface(obj, &IID_IPropertyValue); @@ -937,7 +936,7 @@ static void test_CreateValue(void) ok(hr == S_OK, "got hr %#lx\n", hr); obj = pCreateValue(TYPECODE_STRING, &str); WindowsDeleteString(str); - todo_wine ok(broken(obj != NULL), "got obj %p\n", obj); /* Returns NULL on i386 Windows 10. */ + ok(broken(obj != NULL), "got obj %p\n", obj); /* Returns NULL on i386 Windows 10. */ if (obj) { type = PropertyType_Empty; diff --git a/dlls/vccorlib140/vccorlib.c b/dlls/vccorlib140/vccorlib.c index c6c0139cd9b..6a92994ecf2 100644 --- a/dlls/vccorlib140/vccorlib.c +++ b/dlls/vccorlib140/vccorlib.c @@ -397,9 +397,135 @@ HSTRING __cdecl platform_type_get_FullName(struct platform_type *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) { - FIXME("(%d, %p) stub\n", typecode, val); + IPropertyValueStatics *statics; + IInspectable *obj; + HRESULT hr;
- return NULL; + 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; }
From: Vibhav Pant vibhavp@gmail.com
--- dlls/vccorlib140/vccorlib140.spec | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/dlls/vccorlib140/vccorlib140.spec b/dlls/vccorlib140/vccorlib140.spec index faecd3b8519..d146b07d30e 100644 --- a/dlls/vccorlib140/vccorlib140.spec +++ b/dlls/vccorlib140/vccorlib140.spec @@ -182,7 +182,8 @@ @ stub -arch=i386 ?GetWeakReference@Details@Platform@@YGPAU__abi_IUnknown@@Q$ADVObject@2@@Z @ stub -arch=arm ?GetWeakReference@Details@Platform@@YAPAU__abi_IUnknown@@Q$ADVObject@2@@Z @ stub -arch=win64 ?GetWeakReference@Details@Platform@@YAPEAU__abi_IUnknown@@QE$ADVObject@2@@Z -@ stub -arch=win32 ?InitControlBlock@ControlBlock@Details@Platform@@AAEXPAX_N11@Z +@ stub -arch=i386 ?InitControlBlock@ControlBlock@Details@Platform@@AAEXPAX_N11@Z +@ stub -arch=arm ?InitControlBlock@ControlBlock@Details@Platform@@AAAXPAX_N11@Z @ stub -arch=win64 ?InitControlBlock@ControlBlock@Details@Platform@@AEAAXPEAX_N11@Z @ cdecl ?InitializeData@Details@Platform@@YAJH@Z(long) InitializeData @ stub -arch=win32 ?Intersect@Rect@Foundation@Windows@@QAAXV123@@Z
It fails to compile on ARM due to a typo - check pipeline result for details.
Piotr Caban (@piotr) commented about dlls/vccorlib140/vccorlib.c:
+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))
IAgileObject interface should be implemented separately (and it should be used as IUnknown outer interface in CoCreateFreeThreadedMarshaler).
Piotr Caban (@piotr) commented about dlls/vccorlib140/vccorlib.c:
- }
- 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);
Is there a reason for not using WindowsCreateStringReference here?
Piotr Caban (@piotr) commented about dlls/vccorlib140/vccorlib.c:
+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_vtbl = +{
- /* IUnknown */
Please add comments for all the interfaces or remove this one. There's also an unneeded newline in the structure.
Piotr Caban (@piotr) commented about dlls/vccorlib140/tests/vccorlib.c:
hr = IPropertyValue_GetPoint(obj, &value.point);
break;
case PropertyType_Size:
hr = IPropertyValue_GetSize(obj, &value.size);
break;
case PropertyType_Rect:
hr = IPropertyValue_GetRect(obj, &value.rect);
break;
case PropertyType_Guid:
hr = IPropertyValue_GetGuid(obj, &value.guid);
break;
DEFAULT_UNREACHABLE;
}
ok(hr == S_OK, "got hr %#lx\n", hr);
ok(!memcmp(&test_cases[i].value, &value, sizeof(value)), "got unexpected value\n");
This test is failing on my machine - you will probably need to limit size of compared memory to avoid accessing possibly uninitialized data.
On Mon Aug 25 15:40:27 2025 +0000, Piotr Caban wrote:
It fails to compile on ARM due to a typo - check pipeline result for details.
It's already fixed.
On Mon Aug 25 15:39:37 2025 +0000, Piotr Caban wrote:
IAgileObject interface should be implemented separately (and it should be used as IUnknown outer interface in CoCreateFreeThreadedMarshaler).
I believe all of our WinRT code implements IAgileObject this way. Native seems to do the same thing, as this test:
```c IUnknown_QueryInterface((IUnknown *)type_obj, &IID_IAgileObject, &out); ok(out == type_obj, "got out %p != %p\n", out, type_obj); ```
doesn't fail. Is it still necessary to split this out?
On Mon Aug 25 15:39:37 2025 +0000, Piotr Caban wrote:
Is there a reason for not using WindowsCreateStringReference here?
`WindowsCreateStringReference` requires an additional `HSTRING_HEADER` pointer, to store the string data. The `HSTRING_HEADER` would need to outlive `struct platform_type`, so we can't keep it there. The only other way I can think of is to make it a global, protected with a `ONCE_INIT`, but that feels overkill.
On Mon Aug 25 15:39:38 2025 +0000, Piotr Caban wrote:
Please add comments for all the interfaces or remove this one. There's also an unneeded newline in the structure.
Fixed, thanks.
On Mon Aug 25 15:53:55 2025 +0000, Vibhav Pant wrote:
I believe all of our WinRT code implements IAgileObject this way. Native seems to do the same thing, as this test:
IUnknown_QueryInterface((IUnknown *)type_obj, &IID_IAgileObject, &out); ok(out == type_obj, "got out %p != %p\n", out, type_obj);
doesn't fail. Is it still necessary to split this out?
You can add following test to see what I mean:
``` IUnknown_QueryInterface((IUnknown *)type_obj, &IID_IClosable, &out); ok(out != type_obj, "got out %p != %p\n", out, type_obj); ```
On Mon Aug 25 16:07:27 2025 +0000, Vibhav Pant wrote:
`WindowsCreateStringReference` requires an additional `HSTRING_HEADER` pointer, to store the string data. The `HSTRING_HEADER` would need to outlive `struct platform_type`, so we can't keep it there. The only other way I can think of is to make it a global, protected with a `ONCE_INIT`, but that feels overkill.
I though that it would be simple to use a static header. Let's leave it as is if it's not.
On Mon Aug 25 16:02:48 2025 +0000, Piotr Caban wrote:
You can add following test to see what I mean:
IUnknown_QueryInterface((IUnknown *)type_obj, &IID_IClosable, &out); ok(out != type_obj, "got out %p != %p\n", out, type_obj);
Yes, the pointers are different.
Does anything care? `grep -rI -C4 IsEqualGUID.*IID_IAgileObject` reveals a huge pile of IAgileObject implemented by returning some random interface, and I can't find a single one that returns it separately.
On Mon Aug 25 16:44:58 2025 +0000, Alfred Agrell wrote:
Yes, the pointers are different. Does anything care? `grep -rI -C4 IsEqualGUID.*IID_IAgileObject` reveals a huge pile of IAgileObject implemented by returning some random interface, and I can't find a single one that returns it separately.
I don't know, probably not.