[ATL]
authorThomas Faber <thomas.faber@reactos.org>
Thu, 5 Nov 2015 10:49:52 +0000 (10:49 +0000)
committerThomas Faber <thomas.faber@reactos.org>
Thu, 5 Nov 2015 10:49:52 +0000 (10:49 +0000)
- Implement more CComBSTR methods. Patch by Mark Jansen.
CORE-10478 #resolve

svn path=/trunk/; revision=69815

reactos/lib/atl/atlbase.h
rostests/apitests/atl/CComBSTR.cpp [new file with mode: 0644]
rostests/apitests/atl/CMakeLists.txt
rostests/apitests/atl/atl_apitest.rc [new file with mode: 0644]
rostests/apitests/atl/resource.h [new file with mode: 0644]
rostests/apitests/atl/testlist.c

index 26d59b3..675b96d 100644 (file)
@@ -929,6 +929,11 @@ class CComBSTR
 public:
     BSTR m_str;
 public:
 public:
     BSTR m_str;
 public:
+    CComBSTR() :
+        m_str(NULL)
+    {
+    }
+
     CComBSTR(LPCOLESTR pSrc)
     {
         if (pSrc == NULL)
     CComBSTR(LPCOLESTR pSrc)
     {
         if (pSrc == NULL)
@@ -936,16 +941,116 @@ public:
         else
             m_str = ::SysAllocString(pSrc);
     }
         else
             m_str = ::SysAllocString(pSrc);
     }
+
+    CComBSTR(int length)
+    {
+        if (length == 0)
+            m_str = NULL;
+        else
+            m_str = ::SysAllocStringLen(NULL, length);
+    }
+
+    CComBSTR(int length, LPCOLESTR pSrc)
+    {
+        if (length == 0)
+            m_str = NULL;
+        else
+            m_str = ::SysAllocStringLen(pSrc, length);
+    }
+
+    CComBSTR(PCSTR pSrc)
+    {
+        if (pSrc)
+        {
+            int len = MultiByteToWideChar(CP_THREAD_ACP, 0, pSrc, -1, NULL, 0);
+            m_str = ::SysAllocStringLen(NULL, len - 1);
+            if (m_str)
+            {
+                int res = MultiByteToWideChar(CP_THREAD_ACP, 0, pSrc, -1, m_str, len);
+                ATLASSERT(res == len);
+                if (res != len)
+                {
+                    ::SysFreeString(m_str);
+                    m_str = NULL;
+                }
+            }
+        }
+        else
+        {
+            m_str = NULL;
+        }
+    }
+
+    CComBSTR(const CComBSTR &other)
+    {
+        m_str = other.Copy();
+    }
+
+    CComBSTR(REFGUID guid)
+    {
+        OLECHAR szGuid[40];
+        ::StringFromGUID2(guid, szGuid, 40);
+        m_str = ::SysAllocString(szGuid);
+    }
+
     ~CComBSTR()
     {
         ::SysFreeString(m_str);
         m_str = NULL;
     }
     ~CComBSTR()
     {
         ::SysFreeString(m_str);
         m_str = NULL;
     }
-    
+
     operator BSTR () const
     {
         return m_str;
     }
     operator BSTR () const
     {
         return m_str;
     }
+
+    BSTR *operator & ()
+    {
+        return &m_str;
+    }
+
+    CComBSTR &operator = (const CComBSTR &other)
+    {
+        ::SysFreeString(m_str);
+        m_str = other.Copy();
+        return *this;
+    }
+
+    BSTR Copy() const
+    {
+        if (!m_str)
+            return NULL;
+        return ::SysAllocStringLen(m_str, ::SysStringLen(m_str));
+    }
+
+    HRESULT CopyTo(BSTR *other) const
+    {
+        if (!other)
+            return E_POINTER;
+        *other = Copy();
+        return S_OK;
+    }
+
+    bool LoadString(HMODULE module, DWORD uID)
+    {
+        ::SysFreeString(m_str);
+        m_str = NULL;
+        const wchar_t *ptr = NULL;
+        int len = ::LoadStringW(module, uID, (PWSTR)&ptr, 0);
+        if (len)
+            m_str = ::SysAllocStringLen(ptr, len);
+        return m_str != NULL;
+    }
+
+    unsigned int Length() const
+    {
+        return ::SysStringLen(m_str);
+    }
+
+    unsigned int ByteLength() const
+    {
+        return ::SysStringByteLen(m_str);
+    }
 };
 
 class CComVariant : public tagVARIANT
 };
 
 class CComVariant : public tagVARIANT
diff --git a/rostests/apitests/atl/CComBSTR.cpp b/rostests/apitests/atl/CComBSTR.cpp
new file mode 100644 (file)
index 0000000..e0ad4ce
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * PROJECT:         ReactOS api tests
+ * LICENSE:         LGPLv2.1+ - See COPYING.LIB in the top level directory
+ * PURPOSE:         Test for CComBSTR
+ * PROGRAMMER:      Mark Jansen
+ */
+
+#include <apitest.h>
+#include <atlbase.h>
+#include <atlcom.h>
+#include "resource.h"
+
+#define verify_str       (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : verify_str_imp
+#define verify_str2      (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : verify_str_imp2
+
+
+static void verify_str_imp2(const CComBSTR& comstr, PCWSTR expected, size_t ExpectedLength)
+{
+    BSTR str = (BSTR)comstr;
+    if (expected || ExpectedLength)
+    {
+        winetest_ok(str != NULL, "Expected str to be a valid pointer\n");
+        if (str)
+        {
+            if (expected)
+            {
+                winetest_ok(!wcscmp(str, expected), "Expected the string to be '%s', was '%s'\n", wine_dbgstr_w(expected), wine_dbgstr_w(str));
+            }
+            size_t Length = comstr.Length();
+            winetest_ok(Length == ExpectedLength, "Expected Length to be %u, was: %u\n", ExpectedLength, Length);
+            Length = comstr.ByteLength();
+            ExpectedLength *= sizeof(WCHAR);
+            winetest_ok(Length == ExpectedLength, "Expected ByteLength to be %u, was: %u\n", ExpectedLength, Length);
+        }
+    }
+    else
+    {
+        winetest_ok(str == NULL || str[0] == '\0', "Expected str to be empty, was: '%s'\n", wine_dbgstr_w(str));
+    }
+}
+
+static void verify_str_imp(const CComBSTR& comstr, PCWSTR expected)
+{
+    verify_str_imp2(comstr, expected, expected ? wcslen(expected) : 0);
+}
+
+void test_construction()
+{
+    CComBSTR empty1, empty2;
+    CComBSTR happyW(L"I am a happy BSTR");
+    CComBSTR happyA("I am a happy BSTR");
+    CComBSTR happyW4(4, L"I am a happy BSTR");
+    CComBSTR fromlen1(1), fromlen10(10);
+    CComBSTR fromBSTRW(happyW), fromBSTRA(happyA), fromBSTRW4(happyW4);
+    CComBSTR fromBSTRlen1(fromlen1), fromBSTRlen10(fromlen10);
+
+    verify_str(empty1, NULL);
+    verify_str(empty2, NULL);
+    verify_str(happyW, L"I am a happy BSTR");
+    verify_str(happyA, L"I am a happy BSTR");
+    verify_str(happyW4, L"I am");
+    verify_str2(fromlen1, NULL, 1);
+    verify_str2(fromlen10, NULL, 10);
+    verify_str(fromBSTRW, L"I am a happy BSTR");
+    verify_str(fromBSTRA, L"I am a happy BSTR");
+    verify_str(fromBSTRW4, L"I am");
+    verify_str2(fromBSTRlen1, NULL, 1);
+    verify_str2(fromBSTRlen10, NULL, 10);
+}
+
+void test_copyassignment()
+{
+    CComBSTR happy(L"I am a happy BSTR"), empty, odd;
+    CComBSTR happyCopy1, happyCopy2, emptyCopy, oddCopy;
+
+    odd = ::SysAllocStringByteLen("aaaaa", 3);
+
+    happyCopy1 = happy.Copy();
+    happyCopy2 = happy;    // Calls happyW.Copy()
+    emptyCopy = empty.Copy();
+    oddCopy = odd.Copy();
+
+    verify_str(happy, L"I am a happy BSTR");
+    verify_str(empty, NULL);
+    verify_str2(odd, L"\u6161a", 2);
+    verify_str(happyCopy1, L"I am a happy BSTR");
+    verify_str(happyCopy2, L"I am a happy BSTR");
+    verify_str(emptyCopy, NULL);
+    verify_str2(oddCopy, L"\u6161a", 2);
+    ok((BSTR)happy != (BSTR)happyCopy1, "Expected pointers to be different\n");
+    ok((BSTR)happy != (BSTR)happyCopy2, "Expected pointers to be different\n");
+
+
+    happyCopy1 = (LPCOLESTR)NULL;
+    happyCopy2 = (LPCSTR)NULL;
+
+    verify_str(happyCopy1, NULL);
+    verify_str(happyCopy2, NULL);
+
+    HRESULT hr = happy.CopyTo(&happyCopy1);
+    ok(hr == S_OK, "Expected hr to be E_POINTER, was: %08lx\n", hr);
+
+#if 0
+    // This asserts
+    hr = happy.CopyTo((BSTR*)NULL);
+    ok(hr == E_POINTER, "Expected hr to be E_POINTER, was: %u\n");
+#endif
+}
+
+void test_fromguid()
+{
+    GUID guid = { 0x12345678, 0x9abc, 0xdef0, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0} };
+    CComBSTR fromGuid(guid), empty;
+    verify_str(fromGuid, L"{12345678-9ABC-DEF0-1234-56789ABCDEF0}");
+    verify_str(empty, NULL);
+    empty = fromGuid;
+    verify_str(empty, L"{12345678-9ABC-DEF0-1234-56789ABCDEF0}");
+}
+
+void test_loadres()
+{
+    CComBSTR test1, test2, test3;
+    HMODULE mod = GetModuleHandle(NULL);
+
+    ok(true == test1.LoadString(mod, IDS_TEST1), "Expected LoadString to succeed\n");
+    ok(true == test2.LoadString(mod, IDS_TEST2), "Expected LoadString to succeed\n");
+    ok(false == test3.LoadString(mod, IDS_TEST2 + 1), "Expected LoadString to fail\n");
+
+    verify_str(test1, L"Test string one.");
+    verify_str(test2, L"I am a happy BSTR");
+    verify_str(test3, NULL);
+}
+
+START_TEST(CComBSTR)
+{
+    test_construction();
+    test_copyassignment();
+    test_fromguid();
+    test_loadres();
+}
index d19b3bf..db0bc08 100644 (file)
@@ -4,9 +4,12 @@ set_cpp(WITH_RUNTIME)
 include_directories(${REACTOS_SOURCE_DIR}/lib/atl)
 
 add_executable(atl_apitest
 include_directories(${REACTOS_SOURCE_DIR}/lib/atl)
 
 add_executable(atl_apitest
+    CComBSTR.cpp
     CComHeapPtr.cpp
     CComHeapPtr.cpp
-    testlist.c)
+    testlist.c
+    atl_apitest.rc)
+
 target_link_libraries(atl_apitest wine uuid)
 set_module_type(atl_apitest win32cui)
 target_link_libraries(atl_apitest wine uuid)
 set_module_type(atl_apitest win32cui)
-add_importlibs(atl_apitest ole32 oleaut32 msvcrt kernel32)
+add_importlibs(atl_apitest ole32 oleaut32 user32 msvcrt kernel32)
 add_cd_file(TARGET atl_apitest DESTINATION reactos/bin FOR all)
 add_cd_file(TARGET atl_apitest DESTINATION reactos/bin FOR all)
diff --git a/rostests/apitests/atl/atl_apitest.rc b/rostests/apitests/atl/atl_apitest.rc
new file mode 100644 (file)
index 0000000..760690b
--- /dev/null
@@ -0,0 +1,11 @@
+#include <windef.h>
+#include "resource.h"
+
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+
+STRINGTABLE
+BEGIN
+    IDS_TEST1 "Test string one."
+    IDS_TEST2 "I am a happy BSTR"
+END
+
diff --git a/rostests/apitests/atl/resource.h b/rostests/apitests/atl/resource.h
new file mode 100644 (file)
index 0000000..bc0ff64
--- /dev/null
@@ -0,0 +1,3 @@
+
+#define IDS_TEST1 2000
+#define IDS_TEST2 2001
index 0e626c9..5712c65 100644 (file)
@@ -1,10 +1,12 @@
 #define STANDALONE
 #include <apitest.h>
 
 #define STANDALONE
 #include <apitest.h>
 
+extern void func_CComBSTR(void);
 extern void func_CComHeapPtr(void);
 
 const struct test winetest_testlist[] =
 {
 extern void func_CComHeapPtr(void);
 
 const struct test winetest_testlist[] =
 {
+    { "CComBSTR", func_CComBSTR },
     { "CComHeapPtr", func_CComHeapPtr },
     { 0, 0 }
 };
     { "CComHeapPtr", func_CComHeapPtr },
     { 0, 0 }
 };