From 97b25b3f1e66b31fbc9f42e8b65aec64710be085 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Thu, 15 Nov 2018 14:50:00 -0800 Subject: [PATCH] Add tests for ANSI BSTRs (#20985) * Add tests for ANSI BSTRs * Fix signed/unsigned mismatch in comparisons. Add xplatform include * Use regular memcpy * Enable ANSI BSTR off-windows. * Also enable UnmanagedType.TBStr off-Windows since both BStr variants are available off-Windows. * Make sure the AnsiBSTR marshaller is hooked up off-Windows. * Remove a few more ifdefs I missed. * remove ifdefs around binder definitions and the C# stub helpers. * PR Feedback. * Add xplat ARRAYSIZE macro * Move xplat ARRAYSIZE to platformdefines.h --- .../src/System/StubHelpers.cs | 6 - src/vm/ilmarshalers.cpp | 3 +- src/vm/ilmarshalers.h | 2 - src/vm/mlinfo.cpp | 5 +- src/vm/mscorlib.h | 2 +- src/vm/mtypes.h | 2 +- tests/src/Common/Platform/platformdefines.h | 4 +- tests/src/Interop/CMakeLists.txt | 1 + .../StringMarshalling/AnsiBSTR/AnsiBStrTest.cs | 111 ++++++++++++++++ .../StringMarshalling/AnsiBSTR/AnsiBStrTest.csproj | 41 ++++++ .../AnsiBSTR/AnsiBStrTestNative.cpp | 142 +++++++++++++++++++++ .../StringMarshalling/AnsiBSTR/CMakeLists.txt | 18 +++ .../StringMarshalling/AnsiBSTR/PinvokeDef.cs | 34 +++++ tests/src/Interop/common/xplatform.h | 1 - 14 files changed, 357 insertions(+), 15 deletions(-) create mode 100644 tests/src/Interop/StringMarshalling/AnsiBSTR/AnsiBStrTest.cs create mode 100644 tests/src/Interop/StringMarshalling/AnsiBSTR/AnsiBStrTest.csproj create mode 100644 tests/src/Interop/StringMarshalling/AnsiBSTR/AnsiBStrTestNative.cpp create mode 100644 tests/src/Interop/StringMarshalling/AnsiBSTR/CMakeLists.txt create mode 100644 tests/src/Interop/StringMarshalling/AnsiBSTR/PinvokeDef.cs diff --git a/src/System.Private.CoreLib/src/System/StubHelpers.cs b/src/System.Private.CoreLib/src/System/StubHelpers.cs index 9fa2952..aef67a4 100644 --- a/src/System.Private.CoreLib/src/System/StubHelpers.cs +++ b/src/System.Private.CoreLib/src/System/StubHelpers.cs @@ -394,9 +394,6 @@ namespace System.StubHelpers } } // class VBByValStrMarshaler - -#if FEATURE_COMINTEROP - internal static class AnsiBSTRMarshaler { internal static unsafe IntPtr ConvertToNative(int flags, string strManaged) @@ -445,9 +442,6 @@ namespace System.StubHelpers } } // class AnsiBSTRMarshaler -#endif // FEATURE_COMINTEROP - - internal static class WSTRBufferMarshaler { internal static IntPtr ConvertToNative(string strManaged) diff --git a/src/vm/ilmarshalers.cpp b/src/vm/ilmarshalers.cpp index 2dbf5d0..bf0cf3c 100644 --- a/src/vm/ilmarshalers.cpp +++ b/src/vm/ilmarshalers.cpp @@ -1879,7 +1879,6 @@ void ILBSTRMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit) EmitStoreManagedValue(pslILEmit); } -#ifdef FEATURE_COMINTEROP LocalDesc ILAnsiBSTRMarshaler::GetNativeType() { LIMITED_METHOD_CONTRACT; @@ -1931,6 +1930,8 @@ void ILAnsiBSTRMarshaler::EmitClearNative(ILCodeStream* pslILEmit) pslILEmit->EmitCALL(METHOD__ANSIBSTRMARSHALER__CLEAR_NATIVE, 1, 0); } +#ifdef FEATURE_COMINTEROP + LocalDesc ILHSTRINGMarshaler::GetNativeType() { LIMITED_METHOD_CONTRACT; diff --git a/src/vm/ilmarshalers.h b/src/vm/ilmarshalers.h index 0767fb8..6a67bf6 100644 --- a/src/vm/ilmarshalers.h +++ b/src/vm/ilmarshalers.h @@ -2647,7 +2647,6 @@ protected: virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit); }; -#ifdef FEATURE_COMINTEROP class ILAnsiBSTRMarshaler : public ILMarshaler { public: @@ -2666,7 +2665,6 @@ protected: virtual bool NeedsClearNative(); virtual void EmitClearNative(ILCodeStream* pslILEmit); }; -#endif // FEATURE_COMINTEROP class ILLayoutClassPtrMarshalerBase : public ILMarshaler { diff --git a/src/vm/mlinfo.cpp b/src/vm/mlinfo.cpp index f7fc265..43b39d1 100644 --- a/src/vm/mlinfo.cpp +++ b/src/vm/mlinfo.cpp @@ -2133,7 +2133,7 @@ MarshalInfo::MarshalInfo(Module* pModule, } m_type = MARSHAL_TYPE_BSTR; break; -#ifdef FEATURE_COMINTEROP + case NATIVE_TYPE_ANSIBSTR: if (builder) { @@ -2142,7 +2142,7 @@ MarshalInfo::MarshalInfo(Module* pModule, } m_type = MARSHAL_TYPE_ANSIBSTR; break; - + case NATIVE_TYPE_TBSTR: { if (builder) @@ -2156,6 +2156,7 @@ MarshalInfo::MarshalInfo(Module* pModule, break; } +#ifdef FEATURE_COMINTEROP case NATIVE_TYPE_BYVALSTR: { if (builder) diff --git a/src/vm/mscorlib.h b/src/vm/mscorlib.h index 3cabfc8..b2eb63b 100644 --- a/src/vm/mscorlib.h +++ b/src/vm/mscorlib.h @@ -1079,12 +1079,12 @@ DEFINE_METHOD(BSTRMARSHALER, CONVERT_TO_NATIVE, ConvertToNative, DEFINE_METHOD(BSTRMARSHALER, CONVERT_TO_MANAGED, ConvertToManaged, SM_IntPtr_RetStr) DEFINE_METHOD(BSTRMARSHALER, CLEAR_NATIVE, ClearNative, SM_IntPtr_RetVoid) -#ifdef FEATURE_COMINTEROP DEFINE_CLASS(ANSIBSTRMARSHALER, StubHelpers, AnsiBSTRMarshaler) DEFINE_METHOD(ANSIBSTRMARSHALER, CONVERT_TO_NATIVE, ConvertToNative, SM_Int_Str_RetIntPtr) DEFINE_METHOD(ANSIBSTRMARSHALER, CONVERT_TO_MANAGED, ConvertToManaged, SM_IntPtr_RetStr) DEFINE_METHOD(ANSIBSTRMARSHALER, CLEAR_NATIVE, ClearNative, SM_IntPtr_RetVoid) +#ifdef FEATURE_COMINTEROP DEFINE_CLASS(OBJECTMARSHALER, StubHelpers, ObjectMarshaler) DEFINE_METHOD(OBJECTMARSHALER, CONVERT_TO_NATIVE, ConvertToNative, SM_ObjIntPtr_RetVoid) DEFINE_METHOD(OBJECTMARSHALER, CONVERT_TO_MANAGED, ConvertToManaged, SM_IntPtr_RetObj) diff --git a/src/vm/mtypes.h b/src/vm/mtypes.h index f31ba1f..af21d26 100644 --- a/src/vm/mtypes.h +++ b/src/vm/mtypes.h @@ -43,8 +43,8 @@ DEFINE_MARSHALER_TYPE(MARSHAL_TYPE_LPWSTR, WSTRMarshaler, DEFINE_MARSHALER_TYPE(MARSHAL_TYPE_LPSTR, CSTRMarshaler, false) DEFINE_MARSHALER_TYPE(MARSHAL_TYPE_LPUTF8STR, CUTF8Marshaler, false) DEFINE_MARSHALER_TYPE(MARSHAL_TYPE_BSTR, BSTRMarshaler, false) -#ifdef FEATURE_COMINTEROP DEFINE_MARSHALER_TYPE(MARSHAL_TYPE_ANSIBSTR, AnsiBSTRMarshaler, false) +#ifdef FEATURE_COMINTEROP DEFINE_MARSHALER_TYPE(MARSHAL_TYPE_HSTRING, HSTRINGMarshaler, true) DEFINE_MARSHALER_TYPE(MARSHAL_TYPE_DATETIME, DateTimeMarshaler, true) DEFINE_MARSHALER_TYPE(MARSHAL_TYPE_URI, UriMarshaler, true) diff --git a/tests/src/Common/Platform/platformdefines.h b/tests/src/Common/Platform/platformdefines.h index 498c438..1cc334c 100644 --- a/tests/src/Common/Platform/platformdefines.h +++ b/tests/src/Common/Platform/platformdefines.h @@ -59,6 +59,8 @@ typedef unsigned long ULONG, *PULONG; #define E_INVALIDARG _HRESULT_TYPEDEF_(0x80070057L) #define UInt32x32To64(a, b) ((unsigned __int64)((ULONG)(a)) * (unsigned __int64)((ULONG)(b))) +#define ARRAYSIZE(x) (sizeof(x)/sizeof(*x)) + #ifndef TRUE #define TRUE 1 #endif @@ -141,7 +143,7 @@ void TP_DebugBreak(); DWORD TP_GetFullPathName(LPWSTR fileName, DWORD nBufferLength, LPWSTR lpBuffer); typedef WCHAR* BSTR; -BSTR TP_SysAllocStringByteLen(LPSTR psz, size_t len); +BSTR TP_SysAllocStringByteLen(LPCSTR psz, size_t len); void TP_SysFreeString(BSTR bstr); size_t TP_SysStringByteLen(BSTR bstr); BSTR TP_SysAllocStringLen(LPWSTR psz, size_t len); diff --git a/tests/src/Interop/CMakeLists.txt b/tests/src/Interop/CMakeLists.txt index c509665..cab63b7 100644 --- a/tests/src/Interop/CMakeLists.txt +++ b/tests/src/Interop/CMakeLists.txt @@ -41,6 +41,7 @@ add_subdirectory(StringMarshalling/LPSTR) add_subdirectory(StringMarshalling/LPTSTR) add_subdirectory(StringMarshalling/UTF8) add_subdirectory(StringMarshalling/BSTR) +add_subdirectory(StringMarshalling/AnsiBSTR) add_subdirectory(MarshalAPI/FunctionPointer) add_subdirectory(MarshalAPI/IUnknown) add_subdirectory(SizeConst) diff --git a/tests/src/Interop/StringMarshalling/AnsiBSTR/AnsiBStrTest.cs b/tests/src/Interop/StringMarshalling/AnsiBSTR/AnsiBStrTest.cs new file mode 100644 index 0000000..5fa0ede --- /dev/null +++ b/tests/src/Interop/StringMarshalling/AnsiBSTR/AnsiBStrTest.cs @@ -0,0 +1,111 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.InteropServices; +using System; +using System.Reflection; +using System.Text; +using NativeDefs; +using System.Diagnostics; + +class Test +{ + + #region "Report Failure" + static int fails = 0; //record the fail numbers + // Overload methods for reportfailure + static int ReportFailure(string s) + { + Console.WriteLine(" === Fail:" + s); + return (++fails); + } + static int ReportFailure(string expect, string actual) + { + Console.WriteLine(" === Fail: Expected:" + expect + "\n Actual:" + actual); + return (++fails); + } + static int ReportFailure(string describe, string expect, string actual) + { + Console.WriteLine(" === Fail: " + describe + "\n\tExpected:" + expect + "\n\tActual:" + actual); + return (++fails); + } + #endregion + + #region "Helper" + // ************************************************************ + // Returns the appropriate exit code + // ************************************************************* + static int ExitTest() + { + if (fails == 0) + { + Console.WriteLine("PASS"); + return 100; + } + else + { + Console.WriteLine("FAIL - " + fails + " failure(s) occurred"); + return 101; + } + } + #endregion + + public static int Main(string[] args) + { + string strManaged = " \0Managed\0String\0 "; + string strRet = "a"; + string strNative = "Native String"; + + //since the out attributes doesnt work for string, so i dont check the out value. + string strPara2 = strManaged; + string strRet2 = AnsiBStrTestNative.Marshal_InOut(strPara2); + if (!strRet2.Equals(strRet)) + { + ReportFailure("Method AnsiBStrTestNative.Marshal_InOut[Managed Side],The Return string is wrong", strRet, strRet2); + } + if (!strPara2.Equals(strManaged)) + { + ReportFailure("Method AnsiBStrTestNative.Marshal_InOut[Managed Side],The Parameter string is Changed", strManaged, strPara2); + } + + //TestMethod3 + string strPara3 = strManaged; + string strRet3 = AnsiBStrTestNative.Marshal_Out(strPara3); + if (!strRet.Equals(strRet3)) + { + ReportFailure("Method AnsiBStrTestNative.Marshal_Out[Managed Side],The Return string is wrong", strRet, strRet3); + } + if (!strPara3.Equals(strManaged)) + { + ReportFailure("Method AnsiBStrTestNative.Marshal_Out[Managed Side],The Parameter string is not Changed", strManaged, strPara3); + } + + //TestMethod5 + string strPara5 = strManaged; + string strRet5 = AnsiBStrTestNative.MarshalPointer_InOut(ref strPara5); + + if (!strRet5.Equals(strRet)) + { + ReportFailure("Method AnsiBStrTestNative.MarshalPointer_InOut[Managed Side],The Return string is wrong", strRet, strRet5); + } + if (!strPara5.Equals(strNative)) + { + ReportFailure("Method AnsiBStrTestNative.MarshalPointer_InOut[Managed Side],The Passed string is wrong", strNative, strPara5); + } + + //TestMethod6 + string strPara6 = strManaged; + string strRet6 = AnsiBStrTestNative.MarshalPointer_Out(out strPara6); + if (!strRet6.Equals(strRet)) + { + ReportFailure("Method AnsiBStrTestNative.MarshalPointer_Out[Managed Side],The Return string is wrong", strRet, strRet6); + } + if (!strPara6.Equals(strNative)) + { + ReportFailure("Method AnsiBStrTestNative.MarshalPointer_Out[Managed Side],The Passed string is wrong", strNative, strPara6); + } + + return ExitTest(); + } +} diff --git a/tests/src/Interop/StringMarshalling/AnsiBSTR/AnsiBStrTest.csproj b/tests/src/Interop/StringMarshalling/AnsiBSTR/AnsiBStrTest.csproj new file mode 100644 index 0000000..744f09d --- /dev/null +++ b/tests/src/Interop/StringMarshalling/AnsiBSTR/AnsiBStrTest.csproj @@ -0,0 +1,41 @@ + + + + + Debug + AnyCPU + AnsiBStrTest + 2.0 + {176EC495-7AE9-42CF-A591-06A382DB4048} + exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + true + $(DefineConstants);STATIC + + + + + + + + + False + + + + + + + + + + + {c8c0dc74-fac4-45b1-81fe-70c4808366e0} + CoreCLRTestLibrary + + + + + + diff --git a/tests/src/Interop/StringMarshalling/AnsiBSTR/AnsiBStrTestNative.cpp b/tests/src/Interop/StringMarshalling/AnsiBSTR/AnsiBStrTestNative.cpp new file mode 100644 index 0000000..ca9d92c --- /dev/null +++ b/tests/src/Interop/StringMarshalling/AnsiBSTR/AnsiBStrTestNative.cpp @@ -0,0 +1,142 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +#include +#include "platformdefines.h" + +const char strManaged[] = " \0Managed\0String\0 "; +size_t lenstrManaged = ARRAYSIZE(strManaged) - 1; // the length of strManaged + +const char strReturn[] = "a"; +size_t lenstrReturn = ARRAYSIZE(strReturn) - 1; //the length of strReturn + +const char strNative[] = "Native String"; +size_t lenstrNative = ARRAYSIZE(strNative) - 1; //the len of strNative + +//Test Method1 +extern "C" DLL_EXPORT BSTR STDMETHODCALLTYPE Marshal_In(/*[in]*/ BSTR s) +{ + //Check the input + size_t len = TP_SysStringByteLen(s); + if ((len != lenstrManaged) || (memcmp(s, strManaged, len) != 0)) + { + printf("Error in Function Marshal_In(Native Client)\n"); + + //Expected + printf("Expected:"); + for (size_t i = 0; i < lenstrManaged; ++i) + putchar(*(((char *)strManaged) + i)); + printf("\tThe length of Expected:%zd\n", lenstrManaged); + + //Actual + printf("Actual:"); + for (size_t j = 0; j < len; ++j) + putchar(*(((char *)s) + j)); + printf("\tThe length of Actual:%zd\n", len); + } + + return TP_SysAllocStringByteLen(strReturn, lenstrReturn); +} + +//Test Method2 +extern "C" DLL_EXPORT BSTR STDMETHODCALLTYPE Marshal_InOut(/*[In,Out]*/ BSTR s) +{ + + //Check the Input + size_t len = TP_SysStringByteLen(s); + if ((len != lenstrManaged) || (memcmp(s, strManaged, len) != 0)) + { + printf("Error in Function Marshal_InOut(Native Client)\n"); + + //Expected + printf("Expected:"); + for (size_t i = 0; i < lenstrManaged; ++i) + putchar(*(((char *)strManaged) + i)); + printf("\tThe length of Expected:%zd\n", lenstrManaged); + + //Actual + printf("Actual:"); + for (size_t j = 0; j < len; ++j) + putchar(*(((char *)s) + j)); + printf("\tThe length of Actual:%zd\n", len); + } + + //In-Place Change + memcpy((char *)s, strNative, lenstrNative); + *((UINT *)s - 1) = (UINT) TP_SysStringByteLen(s); + + //Return + return TP_SysAllocStringByteLen(strReturn, lenstrReturn); +} +extern "C" DLL_EXPORT BSTR STDMETHODCALLTYPE Marshal_Out(/*[Out]*/ BSTR s) +{ + s = TP_SysAllocStringByteLen(strNative, lenstrNative); + + //In-Place Change + memcpy((char *)s, strNative, lenstrNative); + *((UINT *)s - 1) = (UINT) TP_SysStringByteLen(s); + + //Return + return TP_SysAllocStringByteLen(strReturn, lenstrReturn); +} + +extern "C" DLL_EXPORT BSTR STDMETHODCALLTYPE MarshalPointer_In(/*[in]*/ BSTR *s) +{ + //CheckInput + size_t len = TP_SysStringByteLen(*s); + if ((len != lenstrManaged) || (memcmp(*s, strManaged, len) != 0)) + { + printf("Error in Function MarshalPointer_In\n"); + + //Expected + printf("Expected:"); + for (size_t i = 0; i < lenstrManaged; ++i) + putchar(*(((char *)strManaged) + i)); + printf("\tThe length of Expected:%zd\n", lenstrManaged); + + //Actual + printf("Actual:"); + for (size_t j = 0; j < len; ++j) + putchar(*(((char *)*s) + j)); + printf("\tThe length of Actual:%zd\n", len); + } + + return TP_SysAllocStringByteLen(strReturn, lenstrReturn); +} + +extern "C" DLL_EXPORT BSTR STDMETHODCALLTYPE MarshalPointer_InOut(/*[in,out]*/ BSTR *s) +{ + //Check the Input + size_t len = TP_SysStringByteLen(*s); + if ((len != lenstrManaged) || (memcmp(*s, strManaged, len) != 0)) + { + printf("Error in Function MarshalPointer_InOut\n"); + + //Expected + printf("Expected:"); + for (size_t i = 0; i < lenstrManaged; ++i) + putchar(*(((char *)strManaged) + i)); + + printf("\tThe length of Expected:%zd\n", lenstrManaged); + + //Actual + printf("Actual:"); + for (size_t j = 0; j < len; ++j) + putchar(*(((char *)*s) + j)); + + printf("\tThe length of Actual:%zd\n", len); + } + + //Allocate New + TP_SysFreeString(*s); + *s = TP_SysAllocStringByteLen(strNative, lenstrNative); + + //Return + return TP_SysAllocStringByteLen(strReturn, lenstrReturn); +} + +extern "C" DLL_EXPORT BSTR STDMETHODCALLTYPE MarshalPointer_Out(/*[out]*/ BSTR *s) +{ + *s = TP_SysAllocStringByteLen(strNative, lenstrNative); + return TP_SysAllocStringByteLen(strReturn, lenstrReturn); +} diff --git a/tests/src/Interop/StringMarshalling/AnsiBSTR/CMakeLists.txt b/tests/src/Interop/StringMarshalling/AnsiBSTR/CMakeLists.txt new file mode 100644 index 0000000..2bf1435 --- /dev/null +++ b/tests/src/Interop/StringMarshalling/AnsiBSTR/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required (VERSION 2.6) +project (AnsiBStrTestNative) +include_directories(${INC_PLATFORM_DIR}) +set(SOURCES AnsiBStrTestNative.cpp) + +# add the executable +add_library (AnsiBStrTestNative SHARED ${SOURCES}) + +if(WIN32) + list(APPEND LINK_LIBRARIES_ADDITIONAL + OleAut32.lib + ) +endif(WIN32) + +target_link_libraries(AnsiBStrTestNative ${LINK_LIBRARIES_ADDITIONAL}) + +# add the install targets +install (TARGETS AnsiBStrTestNative DESTINATION bin) diff --git a/tests/src/Interop/StringMarshalling/AnsiBSTR/PinvokeDef.cs b/tests/src/Interop/StringMarshalling/AnsiBSTR/PinvokeDef.cs new file mode 100644 index 0000000..b77667d --- /dev/null +++ b/tests/src/Interop/StringMarshalling/AnsiBSTR/PinvokeDef.cs @@ -0,0 +1,34 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.InteropServices; +using System; +using System.Reflection; +using System.Text; + +#pragma warning disable CS0618 + +namespace NativeDefs +{ + public static class AnsiBStrTestNative + { + public const string NativeBinaryName = nameof(AnsiBStrTestNative); + + [DllImport(NativeBinaryName)] + [return: MarshalAs(UnmanagedType.AnsiBStr)] + public static extern string Marshal_InOut([In, Out][MarshalAs(UnmanagedType.AnsiBStr)]string s); + + [DllImport(NativeBinaryName)] + [return: MarshalAs(UnmanagedType.AnsiBStr)] + public static extern string Marshal_Out([Out][MarshalAs(UnmanagedType.AnsiBStr)]string s); + + [DllImport(NativeBinaryName)] + [return: MarshalAs(UnmanagedType.AnsiBStr)] + public static extern string MarshalPointer_InOut([MarshalAs(UnmanagedType.AnsiBStr)]ref string s); + + [DllImport(NativeBinaryName)] + [return: MarshalAs(UnmanagedType.AnsiBStr)] + public static extern string MarshalPointer_Out([MarshalAs(UnmanagedType.AnsiBStr)]out string s); + } +} diff --git a/tests/src/Interop/common/xplatform.h b/tests/src/Interop/common/xplatform.h index 158961f..85f0850 100644 --- a/tests/src/Interop/common/xplatform.h +++ b/tests/src/Interop/common/xplatform.h @@ -46,7 +46,6 @@ #else #include "types.h" - #endif #include -- 2.7.4