From 0eaebb31a43736c90862d24f979c5a4dbe976d7d Mon Sep 17 00:00:00 2001 From: Martin Storsjo Date: Tue, 9 Dec 2014 10:36:48 +0200 Subject: combase: Implement creation and deletion of HSTRING objects. --- configure.ac | 1 + .../api-ms-win-core-winrt-string-l1-1-0.spec | 8 +- dlls/combase/Makefile.in | 3 +- dlls/combase/combase.spec | 8 +- dlls/combase/string.c | 143 +++++++++++++++++++++ dlls/combase/tests/Makefile.in | 4 + dlls/combase/tests/string.c | 128 ++++++++++++++++++ tools/make_specfiles | 1 + 8 files changed, 287 insertions(+), 9 deletions(-) create mode 100644 dlls/combase/string.c create mode 100644 dlls/combase/tests/Makefile.in create mode 100644 dlls/combase/tests/string.c diff --git a/configure.ac b/configure.ac index 400ee61..e214189 100644 --- a/configure.ac +++ b/configure.ac @@ -2758,6 +2758,7 @@ WINE_CONFIG_DLL(cards,,[implib]) WINE_CONFIG_DLL(cfgmgr32,,[implib]) WINE_CONFIG_DLL(clusapi,,[implib]) WINE_CONFIG_DLL(combase) +WINE_CONFIG_TEST(dlls/combase/tests) WINE_CONFIG_DLL(comcat) WINE_CONFIG_TEST(dlls/comcat/tests) WINE_CONFIG_DLL(comctl32,,[implib,po]) diff --git a/dlls/api-ms-win-core-winrt-string-l1-1-0/api-ms-win-core-winrt-string-l1-1-0.spec b/dlls/api-ms-win-core-winrt-string-l1-1-0/api-ms-win-core-winrt-string-l1-1-0.spec index bc9035c..7658867 100644 --- a/dlls/api-ms-win-core-winrt-string-l1-1-0/api-ms-win-core-winrt-string-l1-1-0.spec +++ b/dlls/api-ms-win-core-winrt-string-l1-1-0/api-ms-win-core-winrt-string-l1-1-0.spec @@ -8,11 +8,11 @@ @ stub HSTRING_UserUnmarshal64 @ stub WindowsCompareStringOrdinal @ stub WindowsConcatString -@ stub WindowsCreateString -@ stub WindowsCreateStringReference -@ stub WindowsDeleteString +@ stdcall WindowsCreateString(ptr long ptr) combase.WindowsCreateString +@ stdcall WindowsCreateStringReference(wstr long ptr ptr) combase.WindowsCreateStringReference +@ stdcall WindowsDeleteString(ptr) combase.WindowsDeleteString @ stub WindowsDeleteStringBuffer -@ stub WindowsDuplicateString +@ stdcall WindowsDuplicateString(ptr ptr) combase.WindowsDuplicateString @ stub WindowsGetStringLen @ stub WindowsGetStringRawBuffer @ stub WindowsInspectString diff --git a/dlls/combase/Makefile.in b/dlls/combase/Makefile.in index 79d22a1..c5ab8d2 100644 --- a/dlls/combase/Makefile.in +++ b/dlls/combase/Makefile.in @@ -2,4 +2,5 @@ MODULE = combase.dll IMPORTS = ole32 C_SRCS = \ - roapi.c + roapi.c \ + string.c diff --git a/dlls/combase/combase.spec b/dlls/combase/combase.spec index 652eff6..f399d25 100644 --- a/dlls/combase/combase.spec +++ b/dlls/combase/combase.spec @@ -289,11 +289,11 @@ @ stub WdtpInterfacePointer_UserUnmarshal64 @ stub WindowsCompareStringOrdinal @ stub WindowsConcatString -@ stub WindowsCreateString -@ stub WindowsCreateStringReference -@ stub WindowsDeleteString +@ stdcall WindowsCreateString(ptr long ptr) +@ stdcall WindowsCreateStringReference(wstr long ptr ptr) +@ stdcall WindowsDeleteString(ptr) @ stub WindowsDeleteStringBuffer -@ stub WindowsDuplicateString +@ stdcall WindowsDuplicateString(ptr ptr) @ stub WindowsGetStringLen @ stub WindowsGetStringRawBuffer @ stub WindowsInspectString diff --git a/dlls/combase/string.c b/dlls/combase/string.c new file mode 100644 index 0000000..ee2f5c0 --- /dev/null +++ b/dlls/combase/string.c @@ -0,0 +1,143 @@ +/* + * Copyright 2014 Martin Storsjo + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "winerror.h" +#include "hstring.h" +#include "windows.h" +#include "wine/debug.h" +#include + +WINE_DEFAULT_DEBUG_CHANNEL(combase); + +struct hstring_private +{ + LPWSTR buffer; + UINT32 length; + BOOL reference; + LONG refcount; +}; + +C_ASSERT(sizeof(struct hstring_private) <= sizeof(HSTRING_HEADER)); + +static inline struct hstring_private *impl_from_HSTRING(HSTRING string) +{ + return (struct hstring_private *)string; +} + +static inline struct hstring_private *impl_from_HSTRING_HEADER(HSTRING_HEADER *header) +{ + return (struct hstring_private *)header; +} + +static BOOL alloc_string(UINT32 len, HSTRING *out) +{ + struct hstring_private *priv; + priv = HeapAlloc(GetProcessHeap(), 0, sizeof(*priv) + (len + 1) * sizeof(*priv->buffer)); + if (!priv) + return FALSE; + priv->buffer = (LPWSTR)(priv + 1); + priv->length = len; + priv->reference = FALSE; + priv->refcount = 1; + priv->buffer[len] = '\0'; + *out = (HSTRING)priv; + return TRUE; +} + +/*********************************************************************** + * WindowsCreateString (combase.@) + */ +HRESULT WINAPI WindowsCreateString(LPCWSTR ptr, UINT32 len, + HSTRING *out) +{ + struct hstring_private *priv; + if (out == NULL) + return E_INVALIDARG; + if (ptr == NULL && len > 0) + return E_POINTER; + if (len == 0) + { + *out = NULL; + return S_OK; + } + if (!alloc_string(len, out)) + return E_OUTOFMEMORY; + priv = impl_from_HSTRING(*out); + memcpy(priv->buffer, ptr, len * sizeof(*priv->buffer)); + return S_OK; +} + +/*********************************************************************** + * WindowsCreateStringReference (combase.@) + */ +HRESULT WINAPI WindowsCreateStringReference(LPCWSTR ptr, UINT32 len, + HSTRING_HEADER *header, HSTRING *out) +{ + struct hstring_private *priv = impl_from_HSTRING_HEADER(header); + if (out == NULL || header == NULL) + return E_INVALIDARG; + if (ptr == NULL && len > 0) + return E_POINTER; + if (ptr[len] != '\0') + return E_INVALIDARG; + if (len == 0) + { + *out = NULL; + return S_OK; + } + priv->buffer = (LPWSTR)ptr; + priv->length = len; + priv->reference = TRUE; + *out = (HSTRING)header; + return S_OK; +} + +/*********************************************************************** + * WindowsDeleteString (combase.@) + */ +HRESULT WINAPI WindowsDeleteString(HSTRING str) +{ + struct hstring_private *priv = impl_from_HSTRING(str); + if (str == NULL) + return S_OK; + if (priv->reference) + return S_OK; + if (InterlockedDecrement(&priv->refcount) == 0) + HeapFree(GetProcessHeap(), 0, priv); + return S_OK; +} + +/*********************************************************************** + * WindowsDuplicateString (combase.@) + */ +HRESULT WINAPI WindowsDuplicateString(HSTRING str, HSTRING *out) +{ + struct hstring_private *priv = impl_from_HSTRING(str); + if (out == NULL) + return E_INVALIDARG; + if (str == NULL) + { + *out = NULL; + return S_OK; + } + if (priv->reference) + return WindowsCreateString(priv->buffer, priv->length, out); + InterlockedIncrement(&priv->refcount); + *out = str; + return S_OK; +} diff --git a/dlls/combase/tests/Makefile.in b/dlls/combase/tests/Makefile.in new file mode 100644 index 0000000..3e7ecab --- /dev/null +++ b/dlls/combase/tests/Makefile.in @@ -0,0 +1,4 @@ +TESTDLL = combase.dll + +C_SRCS = \ + string.c diff --git a/dlls/combase/tests/string.c b/dlls/combase/tests/string.c new file mode 100644 index 0000000..01a63f7 --- /dev/null +++ b/dlls/combase/tests/string.c @@ -0,0 +1,128 @@ +/* + * Unit tests for Windows String functions + * + * Copyright (c) 2014 Martin Storsjo + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winstring.h" + +#include "wine/test.h" + +static HRESULT (WINAPI *pWindowsCreateString)(LPCWSTR, UINT32, HSTRING *); +static HRESULT (WINAPI *pWindowsCreateStringReference)(LPCWSTR, UINT32, HSTRING_HEADER *, HSTRING *); +static HRESULT (WINAPI *pWindowsDeleteString)(HSTRING); +static HRESULT (WINAPI *pWindowsDuplicateString)(HSTRING, HSTRING *); + +#define SET(x) p##x = (void*)GetProcAddress(hmod, #x) + +static BOOL init_functions(void) +{ + HMODULE hmod = LoadLibraryA("combase.dll"); + if (!hmod) + { + win_skip("Failed to load combase.dll, skipping tests\n"); + return FALSE; + } + SET(WindowsCreateString); + SET(WindowsCreateStringReference); + SET(WindowsDeleteString); + SET(WindowsDuplicateString); + return TRUE; +} + +#undef SET + + +static const WCHAR input_string[] = { 'a', 'b', 'c', 'd', 'e', 'f', '\0' }; +static const WCHAR input_empty_string[] = { '\0' }; + +static void test_create_delete(void) +{ + HSTRING str; + HSTRING_HEADER header; + + /* Test normal creation of a string */ + ok(pWindowsCreateString(input_string, 6, &str) == S_OK, "Failed to create string\n"); + ok(pWindowsDeleteString(str) == S_OK, "Failed to delete string\n"); + /* Test error handling in WindowsCreateString */ + ok(pWindowsCreateString(input_string, 6, NULL) == E_INVALIDARG, "Incorrect error handling\n"); + ok(pWindowsCreateString(NULL, 6, &str) == E_POINTER, "Incorrect error handling\n"); + + /* Test handling of a NULL string */ + ok(pWindowsDeleteString(NULL) == S_OK, "Failed to delete null string\n"); + + /* Test creation of a string reference */ + ok(pWindowsCreateStringReference(input_string, 6, &header, &str) == S_OK, "Failed to create string ref\n"); + ok(pWindowsDeleteString(str) == S_OK, "Failed to delete string ref\n"); + + /* Test error handling in WindowsCreateStringReference */ + /* Strings to CreateStringReference must be null terminated with the correct + * length. According to MSDN this should be E_INVALIDARG, but it returns + * 0x80000017 in practice. */ + ok(FAILED(pWindowsCreateStringReference(input_string, 5, &header, &str)), "Incorrect error handling\n"); + ok(pWindowsCreateStringReference(input_string, 6, NULL, &str) == E_INVALIDARG, "Incorrect error handling\n"); + ok(pWindowsCreateStringReference(input_string, 6, &header, NULL) == E_INVALIDARG, "Incorrect error handling\n"); + ok(pWindowsCreateStringReference(NULL, 6, &header, &str) == E_POINTER, "Incorrect error handling\n"); + + /* Test creating a string without a null-termination at the specified length */ + ok(pWindowsCreateString(input_string, 3, &str) == S_OK, "Failed to create string\n"); + ok(pWindowsDeleteString(str) == S_OK, "Failed to delete string\n"); + + /* Test an empty string */ + ok(pWindowsCreateString(input_empty_string, 0, &str) == S_OK, "Failed to create string\n"); + ok(str == NULL, "Empty string not a null string\n"); + ok(pWindowsDeleteString(str) == S_OK, "Failed to delete string\n"); + + ok(pWindowsCreateStringReference(input_empty_string, 0, &header, &str) == S_OK, "Failed to create string\n"); + ok(str == NULL, "Empty string not a null string\n"); + ok(pWindowsDeleteString(str) == S_OK, "Failed to delete string\n"); +} + +static void test_duplicate(void) +{ + HSTRING str, str2; + HSTRING_HEADER header; + ok(pWindowsCreateString(input_string, 6, &str) == S_OK, "Failed to create string\n"); + ok(pWindowsDuplicateString(str, NULL) == E_INVALIDARG, "Incorrect error handling\n"); + ok(pWindowsDuplicateString(str, &str2) == S_OK, "Failed to duplicate string\n"); + ok(str == str2, "Duplicated string created new string\n"); + ok(pWindowsDeleteString(str) == S_OK, "Failed to delete string\n"); + ok(pWindowsDeleteString(str2) == S_OK, "Failed to delete string\n"); + + ok(pWindowsCreateStringReference(input_string, 6, &header, &str) == S_OK, "Failed to create string ref\n"); + ok(pWindowsDuplicateString(str, &str2) == S_OK, "Failed to duplicate string\n"); + ok(str != str2, "Duplicated string ref didn't create new string\n"); + ok(pWindowsDeleteString(str) == S_OK, "Failed to delete string\n"); + ok(pWindowsDeleteString(str2) == S_OK, "Failed to delete string ref\n"); + + ok(pWindowsDuplicateString(NULL, &str2) == S_OK, "Failed to duplicate NULL string\n"); + ok(str2 == NULL, "Duplicated string created new string\n"); + ok(pWindowsDeleteString(str2) == S_OK, "Failed to delete string\n"); +} + +START_TEST(string) +{ + if (!init_functions()) + return; + test_create_delete(); + test_duplicate(); +} diff --git a/tools/make_specfiles b/tools/make_specfiles index 6e2f3d7..794d00c 100755 --- a/tools/make_specfiles +++ b/tools/make_specfiles @@ -207,6 +207,7 @@ my @dll_groups = [ "combase", "api-ms-win-core-winrt-l1-1-0", + "api-ms-win-core-winrt-string-l1-1-0", ], ); -- 2.1.3