Add tests + implementations for the `HSTRING_User{Size, Marshal, Unmarshal, Free}` methods, required by proxies generated for interfaces that utilize HSTRING.
-- v3: combase: Implement HSTRING_User{Unmarshal, Free}. combase: Implement HSTRING_UserMarshal. combase: Implement HSTRING_UserSize. oleaut32/tests: Add tests for HSTRING marshaling methods.
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/oleaut32/tests/Makefile.in | 2 +- dlls/oleaut32/tests/usrmarshal.c | 103 +++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 1 deletion(-)
diff --git a/dlls/oleaut32/tests/Makefile.in b/dlls/oleaut32/tests/Makefile.in index b8e7615a04e..bc90ca78271 100644 --- a/dlls/oleaut32/tests/Makefile.in +++ b/dlls/oleaut32/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = oleaut32.dll -IMPORTS = oleaut32 ole32 rpcrt4 user32 gdi32 advapi32 +IMPORTS = oleaut32 ole32 rpcrt4 user32 gdi32 advapi32 combase
SOURCES = \ dispatch.c \ diff --git a/dlls/oleaut32/tests/usrmarshal.c b/dlls/oleaut32/tests/usrmarshal.c index 922736b1591..f87859faeda 100644 --- a/dlls/oleaut32/tests/usrmarshal.c +++ b/dlls/oleaut32/tests/usrmarshal.c @@ -28,6 +28,8 @@ #include "objbase.h" #include "propidl.h" /* for LPSAFEARRAY_User* routines */
+#include "winstring.h" +#include "inspectable.h" #include "wine/test.h"
typedef struct @@ -807,6 +809,106 @@ static void test_marshal_BSTR(void) SysFreeString(b); }
+#define ALIGNED_LENGTH(_Len, _Align) (((_Len)+(_Align))&~(_Align)) +#define ALIGNED_POINTER(_Ptr, _Align) ((LPVOID)ALIGNED_LENGTH((ULONG_PTR)(_Ptr), _Align)) +#define ALIGN_LENGTH(_Len, _Align) _Len = ALIGNED_LENGTH(_Len, _Align) +#define ALIGN_POINTER( _Ptr, _Align ) _Ptr = ALIGNED_POINTER( _Ptr, _Align ) + +static void test_marshal_HSTRING(void) +{ + static const WCHAR str_buf[] = L"marshal_test1"; + static const struct test { + const WCHAR *buf; + MSHCTX ctx; + ULONG offset; + ULONG size; + } tests[] = { + {L"", MSHCTX_INPROC, 0, sizeof(HSTRING)*2}, + {L"", MSHCTX_INPROC, 1, ALIGNED_LENGTH(1 + sizeof(HSTRING) * 2, 7)}, + {L"", MSHCTX_LOCAL, 0, 8 }, + {L"", MSHCTX_LOCAL, 1, 16 }, + {L"", MSHCTX_NOSHAREDMEM, 0, 8 }, + {L"", MSHCTX_NOSHAREDMEM, 1, 16 }, + {str_buf, MSHCTX_INPROC, 0, sizeof(HSTRING) * 2 }, + {str_buf, MSHCTX_LOCAL, 0, 8 + (ARRAY_SIZE(str_buf) - 1) * sizeof(WCHAR)}, + {str_buf, MSHCTX_LOCAL, 1, 8 + 8 + (ARRAY_SIZE(str_buf) - 1) * sizeof(WCHAR)}, + {str_buf, MSHCTX_NOSHAREDMEM, 0, 8 + (ARRAY_SIZE(str_buf) - 1) * sizeof(WCHAR)}, + {str_buf, MSHCTX_NOSHAREDMEM, 1, 8 + 8 + (ARRAY_SIZE(str_buf) - 1) * sizeof(WCHAR)} + }; + SIZE_T i; + + for (i = 0; i < ARRAY_SIZE(tests); i++) + { +#ifdef _WIN64 + const ULONG exp_prefix = WDT_INPROC64_CALL; +#else + const ULONG exp_prefix = WDT_INPROC_CALL; +#endif + const struct test *test = &tests[i]; + BOOL empty = !wcslen(test->buf); + MIDL_STUB_MESSAGE stub_msg; + BYTE *buffer, *next, *ptr; + HSTRING str, str2 = NULL; + USER_MARSHAL_CB umcb; + RPC_MESSAGE rpc_msg; + int order = -1; + ULONG size; + HRESULT hr; + + winetest_push_context("tests[%Iu]", i); + hr = WindowsCreateString(test->buf, wcslen(test->buf), &str); + ok(hr == S_OK, "got hr %#lx\n", hr); + + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, test->ctx); + size = HSTRING_UserSize(&umcb.Flags, test->offset, &str); + todo_wine ok(size == test->size, "got size %lu != %lu\n", size, test->size); + + if (size != test->size) + { + WindowsDeleteString(str); + winetest_pop_context(); + continue; + } + + buffer = calloc(1, size); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, test->ctx); + next = HSTRING_UserMarshal(&umcb.Flags, &buffer[test->offset], &str); + todo_wine ok(next == buffer + size, "got next %p != %p\n", next, buffer + size); + ptr = ALIGNED_POINTER(&buffer[test->offset], 7); + todo_wine ok(*(ULONG *)ptr == exp_prefix, "got unexpected prefix %lx\n", *(ULONG *)ptr); + ptr += sizeof(ULONG); + if (test->ctx == MSHCTX_INPROC) + { + ALIGN_POINTER(ptr, sizeof(HSTRING) - 1); + todo_wine_if(!empty) ok(*(DWORD_PTR *)ptr == (DWORD_PTR)str, "got unexpected address %Ix\n", *(DWORD_PTR *)ptr); + } + else + { + ULONG size; + + size = *(ULONG *)ptr; + todo_wine_if(!empty) ok(size == wcslen(test->buf) * sizeof(WCHAR), "got unexpected size %lu\n", *(ULONG *)ptr); + ptr += sizeof(ULONG); + if (size == wcslen(test->buf) * sizeof(WCHAR)) + todo_wine_if(size) ok(!memcmp(ptr, test->buf, size), "got unexpected buffer %s\n", debugstr_wn((WCHAR *)ptr, size)); + } + + next = HSTRING_UserUnmarshal(&umcb.Flags, &buffer[test->offset], &str2); + todo_wine ok(next == buffer + size, "got next %p != %p\n", next, buffer + size); + if (test->ctx == MSHCTX_INPROC || empty) + todo_wine_if(!empty) ok(str2 == str, "got str2 %p != %p\n", str2, str); + else + todo_wine_if(str2) ok(str2 != str, "got str2 %p != %p\n", str2, str); + hr = WindowsCompareStringOrdinal(str, str2, &order); + todo_wine_if(!empty) ok(!order, "got str2 %s != %s\n", debugstr_hstring(str2), debugstr_hstring(str)); + HSTRING_UserFree(&umcb.Flags, &str2); + + free(buffer); + WindowsDeleteString(str); + winetest_pop_context(); + } +} + static inline HeapUnknown *impl_from_IUnknown(IUnknown *iface) { return CONTAINING_RECORD(iface, HeapUnknown, IUnknown_iface); @@ -1758,6 +1860,7 @@ START_TEST(usrmarshal) test_marshal_LPSAFEARRAY(); test_marshal_BSTR(); test_marshal_VARIANT(); + test_marshal_HSTRING();
CoUninitialize(); }
From: Vibhav Pant vibhavp@gmail.com
--- dlls/combase/usrmarshal.c | 9 ++++++++- dlls/oleaut32/tests/usrmarshal.c | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/dlls/combase/usrmarshal.c b/dlls/combase/usrmarshal.c index b3321d8baa8..51cb242635e 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"
@@ -1032,7 +1033,13 @@ void WINAPI WdtpInterfacePointer_UserFree(IUnknown *punk) */ ULONG __RPC_USER HSTRING_UserSize(ULONG *flags, ULONG start, HSTRING *str) { - FIXME("%p, %lu, %p: stub\n", flags, start, str); + TRACE("%s, %lu, %s.\n", debugstr_user_flags(flags), start, debugstr_hstring(*str)); + + ALIGN_LENGTH(start, 7); + if (LOWORD(*flags) == MSHCTX_INPROC) + start += sizeof(*str) * 2; + else + start += sizeof(ULONG64) + WindowsGetStringLen(*str) * sizeof(WCHAR); return start; }
diff --git a/dlls/oleaut32/tests/usrmarshal.c b/dlls/oleaut32/tests/usrmarshal.c index f87859faeda..f25b055b1c5 100644 --- a/dlls/oleaut32/tests/usrmarshal.c +++ b/dlls/oleaut32/tests/usrmarshal.c @@ -861,7 +861,7 @@ static void test_marshal_HSTRING(void)
init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, test->ctx); size = HSTRING_UserSize(&umcb.Flags, test->offset, &str); - todo_wine ok(size == test->size, "got size %lu != %lu\n", size, test->size); + ok(size == test->size, "got size %lu != %lu\n", size, test->size);
if (size != test->size) {
From: Vibhav Pant vibhavp@gmail.com
--- dlls/combase/usrmarshal.c | 38 +++++++++++++++++++++++++++++++- dlls/oleaut32/tests/usrmarshal.c | 10 ++++----- 2 files changed, 42 insertions(+), 6 deletions(-)
diff --git a/dlls/combase/usrmarshal.c b/dlls/combase/usrmarshal.c index 51cb242635e..3302f62338e 100644 --- a/dlls/combase/usrmarshal.c +++ b/dlls/combase/usrmarshal.c @@ -1048,7 +1048,43 @@ ULONG __RPC_USER HSTRING_UserSize(ULONG *flags, ULONG start, HSTRING *str) */ BYTE * __RPC_USER HSTRING_UserMarshal(ULONG *flags, BYTE *buf, HSTRING *str) { - FIXME("%p, %p, %p: stub\n", flags, buf, str); + 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); + return buf; + } + + ALIGN_POINTER(buf, 7); +#ifdef _WIN64 + *(ULONG *)buf = WDT_INPROC64_CALL; +#else + *(ULONG *)buf = WDT_INPROC_CALL; +#endif + buf += sizeof(ULONG); + if (LOWORD(*flags) == MSHCTX_INPROC) + { + HSTRING dup; + + WindowsDuplicateString(*str, &dup); + ALIGN_POINTER(buf, sizeof(*str) - 1); + *(HSTRING *)buf = dup; + buf += sizeof(*str); + } + else + { + UINT32 len, size; + const WCHAR *str_buf; + + str_buf = WindowsGetStringRawBuffer(*str, &len); + *(ULONG *)buf = size = len * sizeof(WCHAR); + buf += sizeof(ULONG); + memcpy(buf, str_buf, size); + buf += size; + } + return buf; }
diff --git a/dlls/oleaut32/tests/usrmarshal.c b/dlls/oleaut32/tests/usrmarshal.c index f25b055b1c5..5b5ef0d215d 100644 --- a/dlls/oleaut32/tests/usrmarshal.c +++ b/dlls/oleaut32/tests/usrmarshal.c @@ -873,24 +873,24 @@ static void test_marshal_HSTRING(void) buffer = calloc(1, size); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, test->ctx); next = HSTRING_UserMarshal(&umcb.Flags, &buffer[test->offset], &str); - 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); ptr = ALIGNED_POINTER(&buffer[test->offset], 7); - todo_wine ok(*(ULONG *)ptr == exp_prefix, "got unexpected prefix %lx\n", *(ULONG *)ptr); + ok(*(ULONG *)ptr == exp_prefix, "got unexpected prefix %lx\n", *(ULONG *)ptr); ptr += sizeof(ULONG); if (test->ctx == MSHCTX_INPROC) { ALIGN_POINTER(ptr, sizeof(HSTRING) - 1); - todo_wine_if(!empty) ok(*(DWORD_PTR *)ptr == (DWORD_PTR)str, "got unexpected address %Ix\n", *(DWORD_PTR *)ptr); + ok(*(DWORD_PTR *)ptr == (DWORD_PTR)str, "got unexpected address %Ix\n", *(DWORD_PTR *)ptr); } else { ULONG size;
size = *(ULONG *)ptr; - todo_wine_if(!empty) ok(size == wcslen(test->buf) * sizeof(WCHAR), "got unexpected size %lu\n", *(ULONG *)ptr); + ok(size == wcslen(test->buf) * sizeof(WCHAR), "got unexpected size %lu\n", *(ULONG *)ptr); ptr += sizeof(ULONG); if (size == wcslen(test->buf) * sizeof(WCHAR)) - todo_wine_if(size) ok(!memcmp(ptr, test->buf, size), "got unexpected buffer %s\n", debugstr_wn((WCHAR *)ptr, size)); + ok(!memcmp(ptr, test->buf, size), "got unexpected buffer %s\n", debugstr_wn((WCHAR *)ptr, size)); }
next = HSTRING_UserUnmarshal(&umcb.Flags, &buffer[test->offset], &str2);
From: Vibhav Pant vibhavp@gmail.com
--- dlls/combase/usrmarshal.c | 36 ++++++++++++++++++++++++++++++-- dlls/oleaut32/tests/usrmarshal.c | 8 +++---- 2 files changed, 38 insertions(+), 6 deletions(-)
diff --git a/dlls/combase/usrmarshal.c b/dlls/combase/usrmarshal.c index 3302f62338e..757e84d6eb7 100644 --- a/dlls/combase/usrmarshal.c +++ b/dlls/combase/usrmarshal.c @@ -1093,7 +1093,36 @@ 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); +#ifdef _WIN64 + static const ULONG prefix = WDT_INPROC64_CALL; +#else + static const ULONG prefix = WDT_INPROC_CALL; +#endif + TRACE("%p, %p, %p\n", debugstr_user_flags(flags), buf, str); + + ALIGN_POINTER(buf, 7); + if (*(ULONG *)buf != prefix) + RpcRaiseException(RPC_S_INVALID_TAG); + buf += sizeof(ULONG); + if (LOWORD(*flags) == MSHCTX_INPROC) + { + ALIGN_POINTER(buf, sizeof(*str) - 1); + *str = *(HSTRING *)buf; + TRACE("str=%s\n", debugstr_hstring(*str)); + buf += sizeof(*str); + } + else + { + UINT32 size; + + size = *(ULONG *)buf; + buf += sizeof(ULONG); + if (size % 2) + RpcRaiseException(RPC_S_INVALID_BOUND); + WindowsCreateString((WCHAR *)buf, size/sizeof(WCHAR), str); + buf += size; + } + return buf; }
@@ -1102,5 +1131,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); } diff --git a/dlls/oleaut32/tests/usrmarshal.c b/dlls/oleaut32/tests/usrmarshal.c index 5b5ef0d215d..308ae42e278 100644 --- a/dlls/oleaut32/tests/usrmarshal.c +++ b/dlls/oleaut32/tests/usrmarshal.c @@ -894,13 +894,13 @@ static void test_marshal_HSTRING(void) }
next = HSTRING_UserUnmarshal(&umcb.Flags, &buffer[test->offset], &str2); - 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); if (test->ctx == MSHCTX_INPROC || empty) - todo_wine_if(!empty) ok(str2 == str, "got str2 %p != %p\n", str2, str); + ok(str2 == str, "got str2 %p != %p\n", str2, str); else - todo_wine_if(str2) ok(str2 != str, "got str2 %p != %p\n", str2, str); + ok(str2 != str, "got str2 %p != %p\n", str2, str); hr = WindowsCompareStringOrdinal(str, str2, &order); - todo_wine_if(!empty) ok(!order, "got str2 %s != %s\n", debugstr_hstring(str2), debugstr_hstring(str)); + ok(!order, "got str2 %s != %s\n", debugstr_hstring(str2), debugstr_hstring(str)); HSTRING_UserFree(&umcb.Flags, &str2);
free(buffer);
The tests should go in combase/tests. For implementation itself, it would be useful to have some wine structures to see what's actually stored. For tests simple linear approach, as we do for BSTR for example, would be more readable. Loops could be useful sometimes, but here it complicates expected values and todos.