Add tests + implementations for the `HSTRING_User{Size, Marshal, Unmarshal, Free}` methods, required by proxies generated for interfaces that utilize HSTRING.
-- v10: combase: Implement HSTRING_User{Unmarshal, Free}.
From: Vibhav Pant vibhavp@gmail.com
--- dlls/combase/combase.spec | 8 ++++---- dlls/combase/usrmarshal.c | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 4 deletions(-)
diff --git a/dlls/combase/combase.spec b/dlls/combase/combase.spec index 7e2d34447a3..6d992d4a675 100644 --- a/dlls/combase/combase.spec +++ b/dlls/combase/combase.spec @@ -220,13 +220,13 @@ @ stdcall HPALETTE_UserMarshal(ptr ptr ptr) @ stdcall HPALETTE_UserSize(ptr long ptr) @ stdcall HPALETTE_UserUnmarshal(ptr ptr ptr) -@ stub HSTRING_UserFree +@ stdcall HSTRING_UserFree(ptr ptr) @ stub -arch=win64 HSTRING_UserFree64 -@ stub HSTRING_UserMarshal +@ stdcall HSTRING_UserMarshal(ptr ptr ptr) @ stub -arch=win64 HSTRING_UserMarshal64 -@ stub HSTRING_UserSize +@ stdcall HSTRING_UserSize(ptr long ptr) @ stub -arch=win64 HSTRING_UserSize64 -@ stub HSTRING_UserUnmarshal +@ stdcall HSTRING_UserUnmarshal(ptr ptr ptr) @ stub -arch=win64 HSTRING_UserUnmarshal64 @ stdcall HWND_UserFree(ptr ptr) @ stdcall HWND_UserMarshal(ptr ptr ptr) diff --git a/dlls/combase/usrmarshal.c b/dlls/combase/usrmarshal.c index 87513d335bf..b3321d8baa8 100644 --- a/dlls/combase/usrmarshal.c +++ b/dlls/combase/usrmarshal.c @@ -22,6 +22,7 @@ #define COBJMACROS #include "ole2.h"
+#include "inspectable.h" #include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(ole); @@ -1025,3 +1026,38 @@ void WINAPI WdtpInterfacePointer_UserFree(IUnknown *punk) TRACE("%p.\n", punk); if (punk) IUnknown_Release(punk); } + +/****************************************************************************** + * HSTRING_UserSize (combase.@) + */ +ULONG __RPC_USER HSTRING_UserSize(ULONG *flags, ULONG start, HSTRING *str) +{ + FIXME("%p, %lu, %p: stub\n", flags, start, str); + return start; +} + +/****************************************************************************** + * HSTRING_UserMarshal (combase.@) + */ +BYTE * __RPC_USER HSTRING_UserMarshal(ULONG *flags, BYTE *buf, HSTRING *str) +{ + FIXME("%p, %p, %p: stub\n", flags, buf, str); + return buf; +} + +/****************************************************************************** + * HSTRING_UserUnmarshal (combase.@) + */ +BYTE * __RPC_USER HSTRING_UserUnmarshal(ULONG *flags, BYTE *buf, HSTRING *str) +{ + FIXME("%p, %p, %p: stub\n", flags, buf, str); + return buf; +} + +/****************************************************************************** + * HSTRING_UserFree (combase.@) + */ +void __RPC_USER HSTRING_UserFree(ULONG *flags, HSTRING *str) +{ + FIXME("%p, %p: stub\n", flags, str); +}
From: Vibhav Pant vibhavp@gmail.com
--- dlls/combase/tests/string.c | 214 ++++++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+)
diff --git a/dlls/combase/tests/string.c b/dlls/combase/tests/string.c index ceb8ffa6e09..aa68639e966 100644 --- a/dlls/combase/tests/string.c +++ b/dlls/combase/tests/string.c @@ -24,6 +24,7 @@ #include "winbase.h" #include "winerror.h" #include "winstring.h" +#include "inspectable.h"
#include "wine/test.h"
@@ -545,6 +546,218 @@ static void test_hstring_struct(void) ok(WindowsDeleteString(str) == S_OK, "Failed to delete string ref.\n"); }
+static void * WINAPI user_allocate(SIZE_T size) +{ + ok(0, "unexpected user_allocate call\n"); + return CoTaskMemAlloc(size); +} + +static void WINAPI user_free(void *p) +{ + ok(0, "unexpected user_free call\n"); + CoTaskMemFree(p); +} + +static void init_user_marshal_cb(USER_MARSHAL_CB *umcb, + PMIDL_STUB_MESSAGE stub_msg, + PRPC_MESSAGE rpc_msg, unsigned char *buffer, + unsigned int size, MSHCTX context) +{ + memset(rpc_msg, 0, sizeof(*rpc_msg)); + rpc_msg->Buffer = buffer; + rpc_msg->BufferLength = size; + + memset(stub_msg, 0, sizeof(*stub_msg)); + stub_msg->RpcMsg = rpc_msg; + stub_msg->Buffer = buffer; + stub_msg->pfnAllocate = user_allocate; + stub_msg->pfnFree = user_free; + + memset(umcb, 0, sizeof(*umcb)); + umcb->Flags = MAKELONG(context, NDR_LOCAL_DATA_REPRESENTATION); + umcb->pStubMsg = stub_msg; + umcb->Signature = USER_MARSHAL_CB_SIGNATURE; + umcb->CBType = buffer ? USER_MARSHAL_CB_UNMARSHALL : USER_MARSHAL_CB_BUFFER_SIZE; +} + +#define ALIGNED_LENGTH(_Len, _Align) (((_Len)+(_Align))&~(_Align)) +#define ALIGNED_POINTER(_Ptr, _Align) ((LPVOID)ALIGNED_LENGTH((ULONG_PTR)(_Ptr), _Align)) + +#pragma pack(push, 1) +struct hstring_wire +{ + /* Marshaling context, either WDT_INPROC64_CALL or WDT_INPROC_CALL. */ + ULONG context; + union { + struct { + ULONG size; + WCHAR data[]; + } buf; + struct { +#ifdef _WIN64 + ULONG pad; +#endif + HSTRING str; + }; + }; +}; +#pragma pack(pop) + +static void test_marshal(void) +{ + static const WCHAR str_buf[] = L"marshal_test1"; + static const ULONG str_len = ARRAY_SIZE(str_buf) - 1; + static const ULONG str_bytes = str_len * sizeof(WCHAR); +#ifdef _WIN64 + const ULONG exp_context = WDT_INPROC64_CALL; +#else + const ULONG exp_context = WDT_INPROC_CALL; +#endif + HSTRING str, str_empty = NULL, str2 = NULL; + const struct hstring_wire *wire; + BYTE *buffer = calloc(1, 80); + MIDL_STUB_MESSAGE stub_msg; + USER_MARSHAL_CB umcb; + ULONG size, exp_size; + RPC_MESSAGE rpc_msg; + INT32 result = -1; + BYTE *next; + HRESULT hr; + + hr = WindowsCreateString(str_buf, wcslen(str_buf), &str); + ok(hr == S_OK, "got hr %#lx\n", hr); + + /* INPROC marshaling */ + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_INPROC); + size = HSTRING_UserSize(&umcb.Flags, 0, &str); + exp_size = sizeof(struct hstring_wire); + todo_wine ok(size == exp_size, "got size %lu != %lu\n", size, exp_size); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_INPROC); + next = HSTRING_UserMarshal(&umcb.Flags, buffer, &str); + if (size == exp_size) + todo_wine ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); + wire = (struct hstring_wire *)buffer; + todo_wine ok(wire->context == exp_context, "got unexpected prefix %#lx != %#lx\n", wire->context, exp_context); + /* INPROC marshaling just consists of increasing the refcount and copying the address. */ + todo_wine ok(wire->str == str, "got unexpected address %p\n", wire->str); + next = HSTRING_UserUnmarshal(&umcb.Flags, buffer, &str2); + if (size == exp_size) + todo_wine ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); + todo_wine ok(str2 == str, "got str2 %p != %p\n", str2, str); + HSTRING_UserFree(&umcb.Flags, &str2); + + /* Test alignment */ + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_INPROC); + size = HSTRING_UserSize(&umcb.Flags, 1, &str); + exp_size = ALIGNED_LENGTH(1 + sizeof(struct hstring_wire), 7); + todo_wine ok(size == exp_size, "got size %lu != %lu\n", size, exp_size); + memset(buffer, 0, 80); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_INPROC); + next = HSTRING_UserMarshal(&umcb.Flags, &buffer[1], &str); + if (size == exp_size) + todo_wine ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); + wire = ALIGNED_POINTER(&buffer[1], 7); + todo_wine ok(wire->context == exp_context, "got unexpected prefix %#lx != %#lx\n", wire->context, exp_context); + todo_wine ok(wire->str == str, "got unexpected address %p\n", wire->str); + next = HSTRING_UserUnmarshal(&umcb.Flags, &buffer[1], &str2); + if (size == exp_size) + todo_wine ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); + todo_wine ok(str2 == str, "got str2 %p != %p\n", str2, str); + HSTRING_UserFree(&umcb.Flags, &str2); + + /* INPROC marshaling with empty/NULL HSTRING */ + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_INPROC); + size = HSTRING_UserSize(&umcb.Flags, 0, &str_empty); + exp_size = sizeof(struct hstring_wire); + todo_wine ok(size == exp_size, "got size %lu != %lu\n", size, exp_size); + memset(buffer, 0xff, 80); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_INPROC); + next = HSTRING_UserMarshal(&umcb.Flags, buffer, &str_empty); + if (size == exp_size) + todo_wine ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); + wire = (struct hstring_wire *)buffer; + todo_wine ok(wire->context == exp_context, "got unexpected prefix %#lx != %#lx\n", wire->context, exp_context); + todo_wine ok(!wire->str, "got unexpected address %p\n", wire->str); + str2 = NULL; + next = HSTRING_UserUnmarshal(&umcb.Flags, buffer, &str2); + if (size == exp_size) + todo_wine ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); + ok(!str2, "got str2 %p\n", str2); + HSTRING_UserFree(&umcb.Flags, &str2); + + /* Out of process marshaling */ + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL); + size = HSTRING_UserSize(&umcb.Flags, 0, &str); + exp_size = offsetof(struct hstring_wire, buf.data[str_len]); + todo_wine ok(size == exp_size, "got size %lu != %lu\n", size, exp_size); + memset(buffer, 0, 80); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); + next = HSTRING_UserMarshal(&umcb.Flags, buffer, &str); + if (size == exp_size) + todo_wine ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); + wire = (struct hstring_wire *)buffer; + todo_wine ok(wire->buf.size == str_bytes, "got buf.size %lu != %lu\n", wire->buf.size, str_bytes); + todo_wine ok(wire->context == exp_context, "got unexpected prefix %#lx != %#lx\n", wire->context, exp_context); + if (size == exp_size) + todo_wine ok(!memcmp(wire->buf.data, str_buf, str_bytes), "got buf.data %s\n", debugstr_wn(wire->buf.data, str_bytes)); + str2 = NULL; + next = HSTRING_UserUnmarshal(&umcb.Flags, buffer, &str2); + if (size == exp_size) + todo_wine ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); + /* A new HSTRING should be allocated */ + todo_wine_if(str2) ok(str2 != str, "got str2 %p\n", str2); + hr = WindowsCompareStringOrdinal(str2, str, &result); + ok(hr == S_OK, "got hr %#lx\n", hr); + todo_wine ok(!result, "got str2 %s != %s\n", debugstr_hstring(str2), debugstr_hstring(str)); + HSTRING_UserFree(&umcb.Flags, &str2); + + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL); + size = HSTRING_UserSize(&umcb.Flags, 1, &str); + exp_size = ALIGNED_LENGTH(1, 7) + offsetof(struct hstring_wire, buf.data[str_len]); + todo_wine ok(size == exp_size, "got size %lu != %lu\n", size, exp_size); + memset(buffer, 0, 80); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); + next = HSTRING_UserMarshal(&umcb.Flags, &buffer[1], &str); + if (size == exp_size) + todo_wine ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); + wire = ALIGNED_POINTER(&buffer[1], 7); + todo_wine ok(wire->buf.size == str_bytes, "got buf.size %lu != %lu\n", wire->buf.size, str_bytes); + todo_wine ok(wire->context == exp_context, "got unexpected prefix %#lx != %#lx\n", wire->context, exp_context); + if (size == exp_size) + todo_wine ok(!memcmp(wire->buf.data, str_buf, str_bytes), "got buf.data %s\n", debugstr_wn(wire->buf.data, str_bytes)); + next = HSTRING_UserUnmarshal(&umcb.Flags, &buffer[1], &str2); + if (size == exp_size) + todo_wine ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); + todo_wine_if(str2) ok(str2 != str, "got str2 %p\n", str2); + result = -1; + hr = WindowsCompareStringOrdinal(str2, str, &result); + ok(hr == S_OK, "got hr %#lx\n", hr); + todo_wine ok(!result, "got str2 %s != %s\n", debugstr_hstring(str2), debugstr_hstring(str)); + HSTRING_UserFree(&umcb.Flags, &str2); + + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL); + size = HSTRING_UserSize(&umcb.Flags, 0, &str_empty); + exp_size = offsetof(struct hstring_wire, buf.data[0]); + todo_wine ok(size == exp_size, "got size %lu != %lu\n", size, exp_size); + memset(buffer, 0xff, 80); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); + next = HSTRING_UserMarshal(&umcb.Flags, buffer, &str_empty); + if (size == exp_size) + todo_wine ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); + wire = (struct hstring_wire *)buffer; + todo_wine ok(wire->context == exp_context, "got unexpected prefix %#lx != %#lx\n", wire->context, exp_context); + todo_wine ok(!wire->buf.size, "got buf.size %lu\n", wire->buf.size); + str2 = NULL; + next = HSTRING_UserUnmarshal(&umcb.Flags, buffer, &str2); + if (size == exp_size) + todo_wine ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); + ok(!str2, "got str2 %p\n", str2); + HSTRING_UserFree(&umcb.Flags, &str2); + + WindowsDeleteString(str); + free(buffer); +} + START_TEST(string) { test_create_delete(); @@ -556,4 +769,5 @@ START_TEST(string) test_compare(); test_trim(); test_hstring_struct(); + test_marshal(); }
From: Vibhav Pant vibhavp@gmail.com
--- dlls/combase/tests/string.c | 12 ++++++------ dlls/combase/usrmarshal.c | 32 +++++++++++++++++++++++++++++--- 2 files changed, 35 insertions(+), 9 deletions(-)
diff --git a/dlls/combase/tests/string.c b/dlls/combase/tests/string.c index aa68639e966..de99cd35ea8 100644 --- a/dlls/combase/tests/string.c +++ b/dlls/combase/tests/string.c @@ -631,7 +631,7 @@ static void test_marshal(void) init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_INPROC); size = HSTRING_UserSize(&umcb.Flags, 0, &str); exp_size = sizeof(struct hstring_wire); - todo_wine ok(size == exp_size, "got size %lu != %lu\n", size, exp_size); + ok(size == exp_size, "got size %lu != %lu\n", size, exp_size); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_INPROC); next = HSTRING_UserMarshal(&umcb.Flags, buffer, &str); if (size == exp_size) @@ -650,7 +650,7 @@ static void test_marshal(void) init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_INPROC); size = HSTRING_UserSize(&umcb.Flags, 1, &str); exp_size = ALIGNED_LENGTH(1 + sizeof(struct hstring_wire), 7); - todo_wine ok(size == exp_size, "got size %lu != %lu\n", size, exp_size); + ok(size == exp_size, "got size %lu != %lu\n", size, exp_size); memset(buffer, 0, 80); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_INPROC); next = HSTRING_UserMarshal(&umcb.Flags, &buffer[1], &str); @@ -669,7 +669,7 @@ static void test_marshal(void) init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_INPROC); size = HSTRING_UserSize(&umcb.Flags, 0, &str_empty); exp_size = sizeof(struct hstring_wire); - todo_wine ok(size == exp_size, "got size %lu != %lu\n", size, exp_size); + ok(size == exp_size, "got size %lu != %lu\n", size, exp_size); memset(buffer, 0xff, 80); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_INPROC); next = HSTRING_UserMarshal(&umcb.Flags, buffer, &str_empty); @@ -689,7 +689,7 @@ static void test_marshal(void) init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL); size = HSTRING_UserSize(&umcb.Flags, 0, &str); exp_size = offsetof(struct hstring_wire, buf.data[str_len]); - todo_wine ok(size == exp_size, "got size %lu != %lu\n", size, exp_size); + ok(size == exp_size, "got size %lu != %lu\n", size, exp_size); memset(buffer, 0, 80); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); next = HSTRING_UserMarshal(&umcb.Flags, buffer, &str); @@ -714,7 +714,7 @@ static void test_marshal(void) init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL); size = HSTRING_UserSize(&umcb.Flags, 1, &str); exp_size = ALIGNED_LENGTH(1, 7) + offsetof(struct hstring_wire, buf.data[str_len]); - todo_wine ok(size == exp_size, "got size %lu != %lu\n", size, exp_size); + ok(size == exp_size, "got size %lu != %lu\n", size, exp_size); memset(buffer, 0, 80); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); next = HSTRING_UserMarshal(&umcb.Flags, &buffer[1], &str); @@ -738,7 +738,7 @@ static void test_marshal(void) init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL); size = HSTRING_UserSize(&umcb.Flags, 0, &str_empty); exp_size = offsetof(struct hstring_wire, buf.data[0]); - todo_wine ok(size == exp_size, "got size %lu != %lu\n", size, exp_size); + ok(size == exp_size, "got size %lu != %lu\n", size, exp_size); memset(buffer, 0xff, 80); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); next = HSTRING_UserMarshal(&umcb.Flags, buffer, &str_empty); diff --git a/dlls/combase/usrmarshal.c b/dlls/combase/usrmarshal.c index b3321d8baa8..0d7743c614e 100644 --- a/dlls/combase/usrmarshal.c +++ b/dlls/combase/usrmarshal.c @@ -22,6 +22,7 @@ #define COBJMACROS #include "ole2.h"
+#include "winstring.h" #include "inspectable.h" #include "wine/debug.h"
@@ -1027,13 +1028,38 @@ void WINAPI WdtpInterfacePointer_UserFree(IUnknown *punk) if (punk) IUnknown_Release(punk); }
+#pragma pack(push, 1) +struct hstring_wire +{ + ULONG context; + union { + struct { + ULONG size; + WCHAR data[]; + } buf; + struct { +#ifdef _WIN64 + ULONG pad; +#endif + HSTRING str; + }; + }; +}; +#pragma pack(pop) + /****************************************************************************** * HSTRING_UserSize (combase.@) */ -ULONG __RPC_USER HSTRING_UserSize(ULONG *flags, ULONG start, HSTRING *str) +ULONG __RPC_USER HSTRING_UserSize(ULONG *flags, ULONG size, HSTRING *str) { - FIXME("%p, %lu, %p: stub\n", flags, start, str); - return start; + TRACE("%s, %lu, %s.\n", debugstr_user_flags(flags), size, debugstr_hstring(*str)); + + ALIGN_LENGTH(size, 7); + if (LOWORD(*flags) == MSHCTX_INPROC) + size += sizeof(struct hstring_wire); + else + size += offsetof(struct hstring_wire, buf.data[WindowsGetStringLen(*str)]); + return size; }
/******************************************************************************
From: Vibhav Pant vibhavp@gmail.com
--- dlls/combase/tests/string.c | 48 ++++++++++++++++--------------------- dlls/combase/usrmarshal.c | 29 +++++++++++++++++++++- 2 files changed, 48 insertions(+), 29 deletions(-)
diff --git a/dlls/combase/tests/string.c b/dlls/combase/tests/string.c index de99cd35ea8..0a07eabc085 100644 --- a/dlls/combase/tests/string.c +++ b/dlls/combase/tests/string.c @@ -634,12 +634,11 @@ static void test_marshal(void) ok(size == exp_size, "got size %lu != %lu\n", size, exp_size); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_INPROC); next = HSTRING_UserMarshal(&umcb.Flags, buffer, &str); - if (size == exp_size) - todo_wine ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); + ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); wire = (struct hstring_wire *)buffer; - todo_wine ok(wire->context == exp_context, "got unexpected prefix %#lx != %#lx\n", wire->context, exp_context); + ok(wire->context == exp_context, "got unexpected prefix %#lx != %#lx\n", wire->context, exp_context); /* INPROC marshaling just consists of increasing the refcount and copying the address. */ - todo_wine ok(wire->str == str, "got unexpected address %p\n", wire->str); + ok(wire->str == str, "got unexpected address %p\n", wire->str); next = HSTRING_UserUnmarshal(&umcb.Flags, buffer, &str2); if (size == exp_size) todo_wine ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); @@ -654,11 +653,10 @@ static void test_marshal(void) memset(buffer, 0, 80); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_INPROC); next = HSTRING_UserMarshal(&umcb.Flags, &buffer[1], &str); - if (size == exp_size) - todo_wine ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); + ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); wire = ALIGNED_POINTER(&buffer[1], 7); - todo_wine ok(wire->context == exp_context, "got unexpected prefix %#lx != %#lx\n", wire->context, exp_context); - todo_wine ok(wire->str == str, "got unexpected address %p\n", wire->str); + ok(wire->context == exp_context, "got unexpected prefix %#lx != %#lx\n", wire->context, exp_context); + ok(wire->str == str, "got unexpected address %p\n", wire->str); next = HSTRING_UserUnmarshal(&umcb.Flags, &buffer[1], &str2); if (size == exp_size) todo_wine ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); @@ -673,11 +671,10 @@ static void test_marshal(void) memset(buffer, 0xff, 80); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_INPROC); next = HSTRING_UserMarshal(&umcb.Flags, buffer, &str_empty); - if (size == exp_size) - todo_wine ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); + ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); wire = (struct hstring_wire *)buffer; - todo_wine ok(wire->context == exp_context, "got unexpected prefix %#lx != %#lx\n", wire->context, exp_context); - todo_wine ok(!wire->str, "got unexpected address %p\n", wire->str); + ok(wire->context == exp_context, "got unexpected prefix %#lx != %#lx\n", wire->context, exp_context); + ok(!wire->str, "got unexpected address %p\n", wire->str); str2 = NULL; next = HSTRING_UserUnmarshal(&umcb.Flags, buffer, &str2); if (size == exp_size) @@ -693,13 +690,11 @@ static void test_marshal(void) memset(buffer, 0, 80); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); next = HSTRING_UserMarshal(&umcb.Flags, buffer, &str); - if (size == exp_size) - todo_wine ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); + ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); wire = (struct hstring_wire *)buffer; - todo_wine ok(wire->buf.size == str_bytes, "got buf.size %lu != %lu\n", wire->buf.size, str_bytes); - todo_wine ok(wire->context == exp_context, "got unexpected prefix %#lx != %#lx\n", wire->context, exp_context); - if (size == exp_size) - todo_wine ok(!memcmp(wire->buf.data, str_buf, str_bytes), "got buf.data %s\n", debugstr_wn(wire->buf.data, str_bytes)); + ok(wire->buf.size == str_bytes, "got buf.size %lu != %lu\n", wire->buf.size, str_bytes); + ok(wire->context == exp_context, "got unexpected prefix %#lx != %#lx\n", wire->context, exp_context); + ok(!memcmp(wire->buf.data, str_buf, str_bytes), "got buf.data %s\n", debugstr_wn(wire->buf.data, str_bytes)); str2 = NULL; next = HSTRING_UserUnmarshal(&umcb.Flags, buffer, &str2); if (size == exp_size) @@ -718,13 +713,11 @@ static void test_marshal(void) memset(buffer, 0, 80); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); next = HSTRING_UserMarshal(&umcb.Flags, &buffer[1], &str); - if (size == exp_size) - todo_wine ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); + ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); wire = ALIGNED_POINTER(&buffer[1], 7); - todo_wine ok(wire->buf.size == str_bytes, "got buf.size %lu != %lu\n", wire->buf.size, str_bytes); - todo_wine ok(wire->context == exp_context, "got unexpected prefix %#lx != %#lx\n", wire->context, exp_context); - if (size == exp_size) - todo_wine ok(!memcmp(wire->buf.data, str_buf, str_bytes), "got buf.data %s\n", debugstr_wn(wire->buf.data, str_bytes)); + ok(wire->buf.size == str_bytes, "got buf.size %lu != %lu\n", wire->buf.size, str_bytes); + ok(wire->context == exp_context, "got unexpected prefix %#lx != %#lx\n", wire->context, exp_context); + ok(!memcmp(wire->buf.data, str_buf, str_bytes), "got buf.data %s\n", debugstr_wn(wire->buf.data, str_bytes)); next = HSTRING_UserUnmarshal(&umcb.Flags, &buffer[1], &str2); if (size == exp_size) todo_wine ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); @@ -742,11 +735,10 @@ static void test_marshal(void) memset(buffer, 0xff, 80); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); next = HSTRING_UserMarshal(&umcb.Flags, buffer, &str_empty); - if (size == exp_size) - todo_wine ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); + ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); wire = (struct hstring_wire *)buffer; - todo_wine ok(wire->context == exp_context, "got unexpected prefix %#lx != %#lx\n", wire->context, exp_context); - todo_wine ok(!wire->buf.size, "got buf.size %lu\n", wire->buf.size); + ok(wire->context == exp_context, "got unexpected prefix %#lx != %#lx\n", wire->context, exp_context); + ok(!wire->buf.size, "got buf.size %lu\n", wire->buf.size); str2 = NULL; next = HSTRING_UserUnmarshal(&umcb.Flags, buffer, &str2); if (size == exp_size) diff --git a/dlls/combase/usrmarshal.c b/dlls/combase/usrmarshal.c index 0d7743c614e..e85145c2328 100644 --- a/dlls/combase/usrmarshal.c +++ b/dlls/combase/usrmarshal.c @@ -1067,7 +1067,34 @@ ULONG __RPC_USER HSTRING_UserSize(ULONG *flags, ULONG size, HSTRING *str) */ BYTE * __RPC_USER HSTRING_UserMarshal(ULONG *flags, BYTE *buf, HSTRING *str) { - FIXME("%p, %p, %p: stub\n", flags, buf, str); + struct hstring_wire *wire; + + TRACE("%s, %p, %s.\n", debugstr_user_flags(flags), buf, debugstr_hstring(*str)); + + if (LOWORD(*flags) == MSHCTX_DIFFERENTMACHINE) + { + FIXME("MSHCTX_DIFFERENTMACHINE is not supported yet.\n"); + RpcRaiseException(RPC_S_INVALID_TAG); + } + + wire = ALIGNED_POINTER(buf, 7); + wire->context = sizeof(*str) == 8 ? WDT_INPROC64_CALL : WDT_INPROC_CALL; + if (LOWORD(*flags) == MSHCTX_INPROC) + { + WindowsDuplicateString(*str, &wire->str); + buf = (BYTE *)(&wire->str + 1); + } + else + { + const WCHAR *str_buf; + UINT32 len; + + str_buf = WindowsGetStringRawBuffer(*str, &len); + wire->buf.size = len * sizeof(WCHAR); + memcpy(wire->buf.data, str_buf, wire->buf.size); + buf = (BYTE*)&wire->buf.data[len]; + } + return buf; }
From: Vibhav Pant vibhavp@gmail.com
--- dlls/combase/tests/string.c | 30 ++++++++++++------------------ dlls/combase/usrmarshal.c | 34 ++++++++++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 20 deletions(-)
diff --git a/dlls/combase/tests/string.c b/dlls/combase/tests/string.c index 0a07eabc085..38bb1aec977 100644 --- a/dlls/combase/tests/string.c +++ b/dlls/combase/tests/string.c @@ -640,9 +640,8 @@ static void test_marshal(void) /* INPROC marshaling just consists of increasing the refcount and copying the address. */ ok(wire->str == str, "got unexpected address %p\n", wire->str); next = HSTRING_UserUnmarshal(&umcb.Flags, buffer, &str2); - if (size == exp_size) - todo_wine ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); - todo_wine ok(str2 == str, "got str2 %p != %p\n", str2, str); + ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); + ok(str2 == str, "got str2 %p != %p\n", str2, str); HSTRING_UserFree(&umcb.Flags, &str2);
/* Test alignment */ @@ -658,9 +657,8 @@ static void test_marshal(void) ok(wire->context == exp_context, "got unexpected prefix %#lx != %#lx\n", wire->context, exp_context); ok(wire->str == str, "got unexpected address %p\n", wire->str); next = HSTRING_UserUnmarshal(&umcb.Flags, &buffer[1], &str2); - if (size == exp_size) - todo_wine ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); - todo_wine ok(str2 == str, "got str2 %p != %p\n", str2, str); + ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); + ok(str2 == str, "got str2 %p != %p\n", str2, str); HSTRING_UserFree(&umcb.Flags, &str2);
/* INPROC marshaling with empty/NULL HSTRING */ @@ -677,8 +675,7 @@ static void test_marshal(void) ok(!wire->str, "got unexpected address %p\n", wire->str); str2 = NULL; next = HSTRING_UserUnmarshal(&umcb.Flags, buffer, &str2); - if (size == exp_size) - todo_wine ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); + ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); ok(!str2, "got str2 %p\n", str2); HSTRING_UserFree(&umcb.Flags, &str2);
@@ -697,13 +694,12 @@ static void test_marshal(void) ok(!memcmp(wire->buf.data, str_buf, str_bytes), "got buf.data %s\n", debugstr_wn(wire->buf.data, str_bytes)); str2 = NULL; next = HSTRING_UserUnmarshal(&umcb.Flags, buffer, &str2); - if (size == exp_size) - todo_wine ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); + ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); /* A new HSTRING should be allocated */ - todo_wine_if(str2) ok(str2 != str, "got str2 %p\n", str2); + ok(str2 != str, "got str2 %p\n", str2); hr = WindowsCompareStringOrdinal(str2, str, &result); ok(hr == S_OK, "got hr %#lx\n", hr); - todo_wine ok(!result, "got str2 %s != %s\n", debugstr_hstring(str2), debugstr_hstring(str)); + ok(!result, "got str2 %s != %s\n", debugstr_hstring(str2), debugstr_hstring(str)); HSTRING_UserFree(&umcb.Flags, &str2);
init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL); @@ -719,13 +715,12 @@ static void test_marshal(void) ok(wire->context == exp_context, "got unexpected prefix %#lx != %#lx\n", wire->context, exp_context); ok(!memcmp(wire->buf.data, str_buf, str_bytes), "got buf.data %s\n", debugstr_wn(wire->buf.data, str_bytes)); next = HSTRING_UserUnmarshal(&umcb.Flags, &buffer[1], &str2); - if (size == exp_size) - todo_wine ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); - todo_wine_if(str2) ok(str2 != str, "got str2 %p\n", str2); + ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); + ok(str2 != str, "got str2 %p\n", str2); result = -1; hr = WindowsCompareStringOrdinal(str2, str, &result); ok(hr == S_OK, "got hr %#lx\n", hr); - todo_wine ok(!result, "got str2 %s != %s\n", debugstr_hstring(str2), debugstr_hstring(str)); + ok(!result, "got str2 %s != %s\n", debugstr_hstring(str2), debugstr_hstring(str)); HSTRING_UserFree(&umcb.Flags, &str2);
init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL); @@ -741,8 +736,7 @@ static void test_marshal(void) ok(!wire->buf.size, "got buf.size %lu\n", wire->buf.size); str2 = NULL; next = HSTRING_UserUnmarshal(&umcb.Flags, buffer, &str2); - if (size == exp_size) - todo_wine ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); + ok(next == &buffer[size], "got next %p != %p\n", next, &buffer[size]); ok(!str2, "got str2 %p\n", str2); HSTRING_UserFree(&umcb.Flags, &str2);
diff --git a/dlls/combase/usrmarshal.c b/dlls/combase/usrmarshal.c index e85145c2328..d28a94baca4 100644 --- a/dlls/combase/usrmarshal.c +++ b/dlls/combase/usrmarshal.c @@ -1103,7 +1103,34 @@ BYTE * __RPC_USER HSTRING_UserMarshal(ULONG *flags, BYTE *buf, HSTRING *str) */ BYTE * __RPC_USER HSTRING_UserUnmarshal(ULONG *flags, BYTE *buf, HSTRING *str) { - FIXME("%p, %p, %p: stub\n", flags, buf, str); + static const ULONG context = sizeof(*str) == 8 ? WDT_INPROC64_CALL : WDT_INPROC_CALL; + const struct hstring_wire *wire; + + TRACE("%p, %p, %p\n", debugstr_user_flags(flags), buf, str); + + wire = ALIGNED_POINTER(buf, 7); + if (wire->context != context) + RpcRaiseException(RPC_S_INVALID_TAG); + if (LOWORD(*flags) == MSHCTX_INPROC) + { + *str = wire->str; + TRACE("str=%s\n", debugstr_hstring(*str)); + buf = (BYTE *)(&wire->str + 1); + } + else + { + UINT32 len; + HRESULT hr; + + if (wire->buf.size % 2) + RpcRaiseException(RPC_S_INVALID_BOUND); + len = wire->buf.size/sizeof(WCHAR); + hr = WindowsCreateString(wire->buf.data, len, str); + if (FAILED(hr)) + RpcRaiseException(HRESULT_CODE(hr)); + buf = (BYTE *)&wire->buf.data[len]; + } + return buf; }
@@ -1112,5 +1139,8 @@ BYTE * __RPC_USER HSTRING_UserUnmarshal(ULONG *flags, BYTE *buf, HSTRING *str) */ void __RPC_USER HSTRING_UserFree(ULONG *flags, HSTRING *str) { - FIXME("%p, %p: stub\n", flags, str); + TRACE("%s, %s.\n", debugstr_user_flags(flags), debugstr_hstring(*str)); + + if (LOWORD(*flags) == MSHCTX_INPROC) + WindowsDeleteString(*str); }
On Mon Aug 4 21:56:36 2025 +0000, Alfred Agrell wrote:
Could try something like
union hstring_wire { struct { ULONG context; } repr1; struct { ULONG context; ULONG size; WCHAR data[]; } repr2; struct { ULONG context; #ifdef _WIN64 ULONG pad; #endif HSTRING str; } repr3; };
and you can read context from any of the members; https://en.cppreference.com/w/c/language/union.html says it will be type-punned, which doesn't do a whole lot of anything when it's ULONG already. (Or you can simply omit the padding member completely, and the compiler will insert the padding if needed. Does winehq have any policy on whether padding members should be explicit?)
I think this will already produce expected padding on 64-bit.
``` struct { ULONG context; HSTRING str; }; ```
If it gets too ugly to have a single structure, I don't see a problem in having two separate types.