diff options
author | Jeremy Koritzinsky <jekoritz@microsoft.com> | 2019-05-24 13:20:23 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-05-24 13:20:23 -0700 |
commit | 73217c884caeca4bcfbb9cc93ffe4c90db79cf7a (patch) | |
tree | 45ee95e94186fab0fabe05bd1aa351567daa62ac | |
parent | 5894a0f4ecd7360dc25b1e01afb0120efceb7a11 (diff) | |
download | coreclr-73217c884caeca4bcfbb9cc93ffe4c90db79cf7a.tar.gz coreclr-73217c884caeca4bcfbb9cc93ffe4c90db79cf7a.tar.bz2 coreclr-73217c884caeca4bcfbb9cc93ffe4c90db79cf7a.zip |
Enable LCID marshalling and clean up our LCID marshalling tests. (#24642)
* Enable LCID marshalling and clean up our LCID marshalling tests.
* Fix return type.
* Enable LCID IDispatch reverse marshalling
* Add more tests for LCID marshalling.
* Add testing for reverse-IDispatch. Fix bug in Thread::GetCulture when culture has not been initialized on the managed side.
* PR Feedback.
* Fix install command.
24 files changed, 683 insertions, 305 deletions
diff --git a/src/vm/dllimport.cpp b/src/vm/dllimport.cpp index 7fc0863a6c..469a06e887 100644 --- a/src/vm/dllimport.cpp +++ b/src/vm/dllimport.cpp @@ -451,8 +451,7 @@ public: STANDARD_VM_CONTRACT; ILCodeStream* pcs = m_slIL.GetDispatchCodeStream(); - -#ifdef FEATURE_USE_LCID + if (SF_IsReverseStub(m_dwStubFlags)) { if ((m_slIL.GetStubTargetCallingConv() & IMAGE_CEE_CS_CALLCONV_HASTHIS) == IMAGE_CEE_CS_CALLCONV_HASTHIS) @@ -504,12 +503,6 @@ public: pcs->EmitCALL(METHOD__CULTURE_INFO__GET_ID, 1, 1); } } -#else // FEATURE_USE_LCID - if (SF_IsForwardStub(m_dwStubFlags)) - { - pcs->EmitLDC(0x0409); // LCID_ENGLISH_US - } -#endif // FEATURE_USE_LCID // add the extra arg to the unmanaged signature LocalDesc locDescNative(ELEMENT_TYPE_I4); diff --git a/src/vm/interoputil.cpp b/src/vm/interoputil.cpp index c516a27eef..a6eab2280e 100644 --- a/src/vm/interoputil.cpp +++ b/src/vm/interoputil.cpp @@ -984,7 +984,6 @@ void GetCultureInfoForLCID(LCID lcid, OBJECTREF *pCultureObj) } CONTRACTL_END; -#ifdef FEATURE_USE_LCID OBJECTREF CultureObj = NULL; GCPROTECT_BEGIN(CultureObj) { @@ -1004,9 +1003,6 @@ void GetCultureInfoForLCID(LCID lcid, OBJECTREF *pCultureObj) *pCultureObj = CultureObj; } GCPROTECT_END(); -#else - COMPlusThrow(kNotSupportedException); -#endif } #endif // CROSSGEN_COMPILE diff --git a/src/vm/mscorlib.h b/src/vm/mscorlib.h index 50188f0407..d328d2a471 100644 --- a/src/vm/mscorlib.h +++ b/src/vm/mscorlib.h @@ -272,10 +272,8 @@ DEFINE_CLASS(CULTURE_INFO, Globalization, CultureInfo) DEFINE_METHOD(CULTURE_INFO, STR_CTOR, .ctor, IM_Str_RetVoid) DEFINE_FIELD(CULTURE_INFO, CURRENT_CULTURE, s_userDefaultCulture) DEFINE_PROPERTY(CULTURE_INFO, NAME, Name, Str) -#ifdef FEATURE_USE_LCID DEFINE_METHOD(CULTURE_INFO, INT_CTOR, .ctor, IM_Int_RetVoid) DEFINE_PROPERTY(CULTURE_INFO, ID, LCID, Int) -#endif DEFINE_FIELD(CULTURE_INFO, CULTURE, s_currentThreadCulture) DEFINE_FIELD(CULTURE_INFO, UI_CULTURE, s_currentThreadUICulture) DEFINE_STATIC_SET_PROPERTY(CULTURE_INFO, CURRENT_CULTURE, CurrentCulture, CultureInfo) diff --git a/src/vm/threads.cpp b/src/vm/threads.cpp index 7632bda555..945cb3a601 100644 --- a/src/vm/threads.cpp +++ b/src/vm/threads.cpp @@ -7918,8 +7918,6 @@ OBJECTREF Thread::GetCulture(BOOL bUICulture) } CONTRACTL_END; - FieldDesc * pFD; - // This is the case when we're building mscorlib and haven't yet created // the system assembly. if (SystemDomain::System()->SystemAssembly()==NULL || g_fForbidEnterEE) { @@ -7927,22 +7925,9 @@ OBJECTREF Thread::GetCulture(BOOL bUICulture) } OBJECTREF pCurrentCulture; - if (bUICulture) { - // Call the Getter for the CurrentUICulture. This will cause it to populate the field. - MethodDescCallSite propGet(METHOD__CULTURE_INFO__GET_CURRENT_UI_CULTURE); - ARG_SLOT retVal = propGet.Call_RetArgSlot(NULL); - pCurrentCulture = ArgSlotToObj(retVal); - } else { - //This is faster than calling the property, because this is what the call does anyway. - pFD = MscorlibBinder::GetField(FIELD__CULTURE_INFO__CURRENT_CULTURE); - _ASSERTE(pFD); - - pFD->CheckRunClassInitThrowing(); - - pCurrentCulture = pFD->GetStaticOBJECTREF(); - _ASSERTE(pCurrentCulture!=NULL); - } - + MethodDescCallSite propGet(bUICulture ? METHOD__CULTURE_INFO__GET_CURRENT_UI_CULTURE : METHOD__CULTURE_INFO__GET_CURRENT_CULTURE); + ARG_SLOT retVal = propGet.Call_RetArgSlot(NULL); + pCurrentCulture = ArgSlotToObj(retVal); return pCurrentCulture; } diff --git a/tests/src/Common/Platform/platformdefines.h b/tests/src/Common/Platform/platformdefines.h index 5f051185f9..c501264aa4 100644 --- a/tests/src/Common/Platform/platformdefines.h +++ b/tests/src/Common/Platform/platformdefines.h @@ -148,7 +148,8 @@ typedef int error_t; typedef void* LPVOID; typedef unsigned char BYTE; typedef WCHAR OLECHAR; -typedef double DATE; +typedef double DATE; +typedef DWORD LCID; #endif typedef ULONG_PTR DWORD_PTR; diff --git a/tests/src/Interop/CMakeLists.txt b/tests/src/Interop/CMakeLists.txt index aa19c68002..b8dc69c31c 100644 --- a/tests/src/Interop/CMakeLists.txt +++ b/tests/src/Interop/CMakeLists.txt @@ -83,6 +83,7 @@ if(WIN32) add_subdirectory(COM/NativeClients/Primitives) add_subdirectory(COM/NativeClients/Licensing) add_subdirectory(COM/NativeClients/DefaultInterfaces) + add_subdirectory(COM/NativeClients/Dispatch) add_subdirectory(WinRT/NativeComponent) # IJW isn't supported on ARM64 diff --git a/tests/src/Interop/COM/NETClients/IDispatch/Program.cs b/tests/src/Interop/COM/NETClients/IDispatch/Program.cs index ad44b300d0..d658bff2c3 100644 --- a/tests/src/Interop/COM/NETClients/IDispatch/Program.cs +++ b/tests/src/Interop/COM/NETClients/IDispatch/Program.cs @@ -5,6 +5,7 @@ namespace NetClient { using System; + using System.Globalization; using System.Reflection; using System.Runtime.InteropServices; @@ -151,6 +152,24 @@ namespace NetClient Assert.Throws<NotSupportedException>(() => dispatchTesting.DoubleHVAValues(ref input)); } + static void Validate_LCID_Marshaled() + { + var dispatchTesting = (DispatchTesting)new DispatchTestingClass(); + CultureInfo oldCulture = CultureInfo.CurrentCulture; + CultureInfo newCulture = new CultureInfo("es-ES", false); + try + { + CultureInfo englishCulture = new CultureInfo("en-US", false); + CultureInfo.CurrentCulture = newCulture; + int lcid = dispatchTesting.PassThroughLCID(); + Assert.AreEqual(englishCulture.LCID, lcid); // CLR->Dispatch LCID marshalling is explicitly hardcoded to en-US instead of passing the current culture. + } + finally + { + CultureInfo.CurrentCulture = oldCulture; + } + } + static int Main(string[] doNotUse) { // RegFree COM is not supported on Windows Nano @@ -166,6 +185,7 @@ namespace NetClient Validate_Double_In_ReturnAndUpdateByRef(); Validate_Exception(); Validate_StructNotSupported(); + Validate_LCID_Marshaled(); } catch (Exception e) { diff --git a/tests/src/Interop/COM/NETClients/Primitives/StringTests.cs b/tests/src/Interop/COM/NETClients/Primitives/StringTests.cs index 0c1212ceae..5b2bc4bed5 100644 --- a/tests/src/Interop/COM/NETClients/Primitives/StringTests.cs +++ b/tests/src/Interop/COM/NETClients/Primitives/StringTests.cs @@ -6,6 +6,7 @@ namespace NetClient { using System; using System.Collections.Generic; + using System.Globalization; using System.Linq; using System.Text; using System.Runtime.InteropServices; @@ -54,6 +55,7 @@ namespace NetClient this.Marshal_LPString(); this.Marshal_LPWString(); this.Marshal_BStrString(); + this.Marshal_LCID(); } static private string Reverse(string s) @@ -267,5 +269,32 @@ namespace NetClient Assert.AreEqual(local, actual); } } + + private void Marshal_LCID() + { + Console.WriteLine("Marshal LCID"); + foreach (var s in reversableStrings) + { + string local = s; + string expected = Reverse(local); + + string actual = this.server.Reverse_LPWStr_With_LCID(local); + Assert.AreEqual(expected, actual); + } + + CultureInfo culture = new CultureInfo("es-ES", false); + CultureInfo englishCulture = new CultureInfo("en-US", false); + CultureInfo oldCulture = CultureInfo.CurrentCulture; + try + { + CultureInfo.CurrentCulture = culture; + this.server.Pass_Through_LCID(out int lcid); + Assert.AreEqual(englishCulture.LCID, lcid); // CLR->COM LCID marshalling is explicitly hardcoded to en-US as requested by VSTO instead of passing the current culture. + } + finally + { + CultureInfo.CurrentCulture = oldCulture; + } + } } } diff --git a/tests/src/Interop/COM/NETServer/DispatchTesting.cs b/tests/src/Interop/COM/NETServer/DispatchTesting.cs new file mode 100644 index 0000000000..683fa88a9a --- /dev/null +++ b/tests/src/Interop/COM/NETServer/DispatchTesting.cs @@ -0,0 +1,79 @@ +// 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; +using System.Globalization; +using System.Text; +using System.Runtime.InteropServices; +using Server.Contract; + +[ComVisible(true)] +[Guid(Server.Contract.Guids.DispatchTesting)] +public class DispatchTesting : Server.Contract.IDispatchTesting +{ + public void DoubleNumeric_ReturnByRef ( + byte b1, + ref byte b2, + short s1, + ref short s2, + ushort us1, + ref ushort us2, + int i1, + ref int i2, + uint ui1, + ref uint ui2, + long l1, + ref long l2, + ulong ul1, + ref ulong ul2) + { + b2 = (byte)(b1 * 2); + s2 = (short)(s1 * 2); + us2 = (ushort)(us1 * 2); + i2 = i1 * 2; + ui2 = ui1 * 2; + l2 = l1 * 2; + ul2 = ul1 * 2; + } + + public float Add_Float_ReturnAndUpdateByRef(float a, ref float b) + { + float sum = a + b; + b = sum; + return sum; + } + public double Add_Double_ReturnAndUpdateByRef(double a, ref double b) + { + double sum = a + b; + b = sum; + return sum; + } + + public void TriggerException(IDispatchTesting_Exception excep, int errorCode) + { + switch (excep) + { + case IDispatchTesting_Exception.Disp: + throw new Exception(); + case IDispatchTesting_Exception.HResult: + throw new System.ComponentModel.Win32Exception(errorCode); + } + } + + // Special cases + public HFA_4 DoubleHVAValues(ref HFA_4 input) + { + input.x *= 2; + input.y *= 2; + input.z *= 2; + input.w *= 2; + return input; + } + + [LCIDConversion(0)] + public int PassThroughLCID() + { + return CultureInfo.CurrentCulture.LCID; + } +} diff --git a/tests/src/Interop/COM/NETServer/StringTesting.cs b/tests/src/Interop/COM/NETServer/StringTesting.cs index c47a155f29..e002ba0de9 100644 --- a/tests/src/Interop/COM/NETServer/StringTesting.cs +++ b/tests/src/Interop/COM/NETServer/StringTesting.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Globalization; using System.Text; using System.Runtime.InteropServices; @@ -191,4 +192,18 @@ public class StringTesting : Server.Contract.IStringTesting { b = Reverse(a); } + + + [LCIDConversion(1)] + [return:MarshalAs(UnmanagedType.LPWStr)] + public string Reverse_LPWStr_With_LCID([MarshalAs(UnmanagedType.LPWStr)] string a) + { + return Reverse(a); + } + + [LCIDConversion(0)] + public void Pass_Through_LCID(out int lcid) + { + lcid = CultureInfo.CurrentCulture.LCID; + } } diff --git a/tests/src/Interop/COM/NativeClients/Dispatch.csproj b/tests/src/Interop/COM/NativeClients/Dispatch.csproj new file mode 100644 index 0000000000..8fc786ad61 --- /dev/null +++ b/tests/src/Interop/COM/NativeClients/Dispatch.csproj @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <IgnoreCoreCLRTestLibraryDependency>true</IgnoreCoreCLRTestLibraryDependency> + <CLRTestScriptLocalCoreShim>true</CLRTestScriptLocalCoreShim> + <RequiresMockHostPolicy>true</RequiresMockHostPolicy> + <IlrtTestKind>BuildOnly</IlrtTestKind> + + <TestUnsupportedOutsideWindows>true</TestUnsupportedOutsideWindows> + <DisableProjectBuild Condition="'$(TargetsUnix)' == 'true'">true</DisableProjectBuild> + <DefineConstants>BLOCK_WINDOWS_NANO</DefineConstants> + </PropertyGroup> + <ItemGroup> + <Compile Include="$(InteropCommonDir)ExeLauncherProgram.cs" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="Dispatch/CMakeLists.txt" /> + <ProjectReference Include="../NetServer/NetServer.csproj" /> + <ProjectReference Include="../../../Common/CoreCLRTestLibrary/CoreCLRTestLibrary.csproj" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), Interop.settings.targets))\Interop.settings.targets" /> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> +</Project> diff --git a/tests/src/Interop/COM/NativeClients/Dispatch/App.manifest b/tests/src/Interop/COM/NativeClients/Dispatch/App.manifest new file mode 100644 index 0000000000..ed665080a7 --- /dev/null +++ b/tests/src/Interop/COM/NativeClients/Dispatch/App.manifest @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> + <assemblyIdentity + type="win32" + name="COMClientPrimitives" + version="1.0.0.0"/> + + <dependency> + <dependentAssembly> + <!-- RegFree COM - CoreCLR Shim --> + <assemblyIdentity + type="win32" + name="CoreShim.X" + version="1.0.0.0"/> + </dependentAssembly> + </dependency> +</assembly>
\ No newline at end of file diff --git a/tests/src/Interop/COM/NativeClients/Dispatch/CMakeLists.txt b/tests/src/Interop/COM/NativeClients/Dispatch/CMakeLists.txt new file mode 100644 index 0000000000..e6d874591f --- /dev/null +++ b/tests/src/Interop/COM/NativeClients/Dispatch/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required (VERSION 2.6) + +include_directories( ${INC_PLATFORM_DIR} ) +include_directories( "../../ServerContracts" ) +include_directories( "../../NativeServer" ) +set(SOURCES + Client.cpp + App.manifest) + +# add the executable +add_executable (COMClientDispatch ${SOURCES}) +target_link_libraries(COMClientDispatch ${LINK_LIBRARIES_ADDITIONAL}) + +# Copy CoreShim manifest to project output +file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/CoreShim.X.manifest INPUT ${CMAKE_CURRENT_SOURCE_DIR}/CoreShim.X.manifest) + +# add the install targets +install (TARGETS COMClientDispatch DESTINATION bin) diff --git a/tests/src/Interop/COM/NativeClients/Dispatch/Client.cpp b/tests/src/Interop/COM/NativeClients/Dispatch/Client.cpp new file mode 100644 index 0000000000..de303fc37a --- /dev/null +++ b/tests/src/Interop/COM/NativeClients/Dispatch/Client.cpp @@ -0,0 +1,309 @@ +// 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 "ClientTests.h" +#include <memory> + + +void Validate_Numeric_In_ReturnByRef(); +void Validate_Float_In_ReturnAndUpdateByRef(); +void Validate_Double_In_ReturnAndUpdateByRef(); +void Validate_LCID_Marshaled(); + +template<COINIT TM> +struct ComInit +{ + const HRESULT Result; + + ComInit() + : Result{ ::CoInitializeEx(nullptr, TM) } + { } + + ~ComInit() + { + if (SUCCEEDED(Result)) + ::CoUninitialize(); + } +}; + +using ComMTA = ComInit<COINIT_MULTITHREADED>; + +int __cdecl main() +{ + ComMTA init; + if (FAILED(init.Result)) + return -1; + + try + { + Validate_Numeric_In_ReturnByRef(); + Validate_Float_In_ReturnAndUpdateByRef(); + Validate_Double_In_ReturnAndUpdateByRef(); + Validate_LCID_Marshaled(); + } + catch (HRESULT hr) + { + ::printf("Test Failure: 0x%08x\n", hr); + return 101; + } + + return 100; +} + +void Validate_Numeric_In_ReturnByRef() +{ + HRESULT hr; + + CoreShimComActivation csact{ W("NETServer"), W("DispatchTesting") }; + + ComSmartPtr<IDispatchTesting> dispatchTesting; + THROW_IF_FAILED(::CoCreateInstance(CLSID_DispatchTesting, nullptr, CLSCTX_INPROC, IID_IDispatchTesting, (void**)&dispatchTesting)); + + LPOLESTR numericMethodName = (LPOLESTR)W("DoubleNumeric_ReturnByRef"); + LCID lcid = MAKELCID(LANG_USER_DEFAULT, SORT_DEFAULT); + DISPID methodId; + + THROW_IF_FAILED(dispatchTesting->GetIDsOfNames( + IID_NULL, + &numericMethodName, + 1, + lcid, + &methodId)); + + BYTE b1 = 24; + BYTE b2; + SHORT s1 = 53; + SHORT s2; + USHORT us1 = 74; + USHORT us2; + LONG i1 = 34; + LONG i2; + ULONG ui1 = 854; + ULONG ui2; + LONGLONG l1 = 894; + LONGLONG l2; + ULONGLONG ul1 = 4168; + ULONGLONG ul2; + + DISPPARAMS params; + params.cArgs = 14; + params.rgvarg = new VARIANTARG[params.cArgs]; + params.cNamedArgs = 0; + params.rgdispidNamedArgs = nullptr; + + V_VT(¶ms.rgvarg[13]) = VT_UI1; + V_UI1(¶ms.rgvarg[13]) = b1; + V_VT(¶ms.rgvarg[12]) = VT_BYREF | VT_UI1; + V_UI1REF(¶ms.rgvarg[12]) = &b2; + V_VT(¶ms.rgvarg[11]) = VT_I2; + V_I2(¶ms.rgvarg[11]) = s1; + V_VT(¶ms.rgvarg[10]) = VT_BYREF | VT_I2; + V_I2REF(¶ms.rgvarg[10]) = &s2; + V_VT(¶ms.rgvarg[9]) = VT_UI2; + V_UI2(¶ms.rgvarg[9]) = us1; + V_VT(¶ms.rgvarg[8]) = VT_BYREF | VT_UI2; + V_UI2REF(¶ms.rgvarg[8]) = &us2; + V_VT(¶ms.rgvarg[7]) = VT_I4; + V_I4(¶ms.rgvarg[7]) = i1; + V_VT(¶ms.rgvarg[6]) = VT_BYREF | VT_I4; + V_I4REF(¶ms.rgvarg[6]) = &i2; + V_VT(¶ms.rgvarg[5]) = VT_UI4; + V_UI4(¶ms.rgvarg[5]) = ui1; + V_VT(¶ms.rgvarg[4]) = VT_BYREF | VT_UI4; + V_UI4REF(¶ms.rgvarg[4]) = &ui2; + V_VT(¶ms.rgvarg[3]) = VT_I8; + V_I8(¶ms.rgvarg[3]) = l1; + V_VT(¶ms.rgvarg[2]) = VT_BYREF | VT_I8; + V_I8REF(¶ms.rgvarg[2]) = &l2; + V_VT(¶ms.rgvarg[1]) = VT_UI8; + V_UI8(¶ms.rgvarg[1]) = ul1; + V_VT(¶ms.rgvarg[0]) = VT_BYREF | VT_UI8; + V_UI8REF(¶ms.rgvarg[0]) = &ul2; + + THROW_IF_FAILED(dispatchTesting->Invoke( + methodId, + IID_NULL, + lcid, + DISPATCH_METHOD, + ¶ms, + nullptr, + nullptr, + nullptr + )); + + THROW_FAIL_IF_FALSE(b2 == b1 * 2); + THROW_FAIL_IF_FALSE(s2 == s1 * 2); + THROW_FAIL_IF_FALSE(us2 == us1 * 2); + THROW_FAIL_IF_FALSE(i2 == i1 * 2); + THROW_FAIL_IF_FALSE(ui2 == ui1 * 2); + THROW_FAIL_IF_FALSE(l2 == l1 * 2); + THROW_FAIL_IF_FALSE(ul2 == ul1 * 2); +} + +namespace +{ + bool EqualByBound(float expected, float actual) + { + float low = expected - 0.0001f; + float high = expected + 0.0001f; + float eps = abs(expected - actual); + return eps < std::numeric_limits<float>::epsilon() || (low < actual && actual < high); + } + + bool EqualByBound(double expected, double actual) + { + double low = expected - 0.00001; + double high = expected + 0.00001; + double eps = abs(expected - actual); + return eps < std::numeric_limits<double>::epsilon() || (low < actual && actual < high); + } +} + +void Validate_Float_In_ReturnAndUpdateByRef() +{ + HRESULT hr; + + CoreShimComActivation csact{ W("NETServer"), W("DispatchTesting") }; + + ComSmartPtr<IDispatchTesting> dispatchTesting; + THROW_IF_FAILED(::CoCreateInstance(CLSID_DispatchTesting, nullptr, CLSCTX_INPROC, IID_IDispatchTesting, (void**)&dispatchTesting)); + + LPOLESTR numericMethodName = (LPOLESTR)W("Add_Float_ReturnAndUpdateByRef"); + LCID lcid = MAKELCID(LANG_USER_DEFAULT, SORT_DEFAULT); + DISPID methodId; + + THROW_IF_FAILED(dispatchTesting->GetIDsOfNames( + IID_NULL, + &numericMethodName, + 1, + lcid, + &methodId)); + + float a = 12.34f; + float b = 1.234f; + float expected = b + a; + + DISPPARAMS params; + params.cArgs = 2; + params.rgvarg = new VARIANTARG[params.cArgs]; + params.cNamedArgs = 0; + params.rgdispidNamedArgs = nullptr; + + VARIANT result; + + V_VT(¶ms.rgvarg[1]) = VT_R4; + V_R4(¶ms.rgvarg[1]) = a; + V_VT(¶ms.rgvarg[0]) = VT_BYREF | VT_R4; + V_R4REF(¶ms.rgvarg[0]) = &b; + + + THROW_IF_FAILED(dispatchTesting->Invoke( + methodId, + IID_NULL, + lcid, + DISPATCH_METHOD, + ¶ms, + &result, + nullptr, + nullptr + )); + + THROW_FAIL_IF_FALSE(EqualByBound(expected, V_R4(&result))); + THROW_FAIL_IF_FALSE(EqualByBound(expected, b)); +} + +void Validate_Double_In_ReturnAndUpdateByRef() +{ + HRESULT hr; + + CoreShimComActivation csact{ W("NETServer"), W("DispatchTesting") }; + + ComSmartPtr<IDispatchTesting> dispatchTesting; + THROW_IF_FAILED(::CoCreateInstance(CLSID_DispatchTesting, nullptr, CLSCTX_INPROC, IID_IDispatchTesting, (void**)&dispatchTesting)); + + LPOLESTR numericMethodName = (LPOLESTR)W("Add_Double_ReturnAndUpdateByRef"); + LCID lcid = MAKELCID(LANG_USER_DEFAULT, SORT_DEFAULT); + DISPID methodId; + + THROW_IF_FAILED(dispatchTesting->GetIDsOfNames( + IID_NULL, + &numericMethodName, + 1, + lcid, + &methodId)); + + double a = 1856.5634; + double b = 587867.757; + double expected = a + b; + + DISPPARAMS params; + params.cArgs = 2; + params.rgvarg = new VARIANTARG[params.cArgs]; + params.cNamedArgs = 0; + params.rgdispidNamedArgs = nullptr; + + VARIANT result; + + V_VT(¶ms.rgvarg[1]) = VT_R8; + V_R8(¶ms.rgvarg[1]) = a; + V_VT(¶ms.rgvarg[0]) = VT_BYREF | VT_R8; + V_R8REF(¶ms.rgvarg[0]) = &b; + + + THROW_IF_FAILED(dispatchTesting->Invoke( + methodId, + IID_NULL, + lcid, + DISPATCH_METHOD, + ¶ms, + &result, + nullptr, + nullptr + )); + + THROW_FAIL_IF_FALSE(EqualByBound(expected, V_R8(&result))); + THROW_FAIL_IF_FALSE(EqualByBound(expected, b)); +} + +void Validate_LCID_Marshaled() +{ + HRESULT hr; + + CoreShimComActivation csact{ W("NETServer"), W("DispatchTesting") }; + + ComSmartPtr<IDispatchTesting> dispatchTesting; + THROW_IF_FAILED(::CoCreateInstance(CLSID_DispatchTesting, nullptr, CLSCTX_INPROC, IID_IDispatchTesting, (void**)&dispatchTesting)); + + LPOLESTR numericMethodName = (LPOLESTR)W("PassThroughLCID"); + LCID lcid = MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_CHILE), SORT_DEFAULT); + DISPID methodId; + + THROW_IF_FAILED(dispatchTesting->GetIDsOfNames( + IID_NULL, + &numericMethodName, + 1, + lcid, + &methodId)); + + DISPPARAMS params; + params.cArgs = 0; + params.rgvarg = nullptr; + params.cNamedArgs = 0; + params.rgdispidNamedArgs = nullptr; + + VARIANT result; + + THROW_IF_FAILED(dispatchTesting->Invoke( + methodId, + IID_NULL, + lcid, + DISPATCH_METHOD, + ¶ms, + &result, + nullptr, + nullptr + )); + + THROW_FAIL_IF_FALSE(lcid == V_I4(&result)); +} diff --git a/tests/src/Interop/COM/NativeClients/Dispatch/ClientTests.h b/tests/src/Interop/COM/NativeClients/Dispatch/ClientTests.h new file mode 100644 index 0000000000..58a524ec0b --- /dev/null +++ b/tests/src/Interop/COM/NativeClients/Dispatch/ClientTests.h @@ -0,0 +1,13 @@ +// 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 <xplatform.h> +#include <cassert> +#include <Server.Contracts.h> + +#define COM_CLIENT +#include <Servers.h> + +#define THROW_IF_FAILED(exp) { hr = exp; if (FAILED(hr)) { ::printf("FAILURE: 0x%08x = %s\n", hr, #exp); throw hr; } } +#define THROW_FAIL_IF_FALSE(exp) { if (!(exp)) { ::printf("FALSE: %s\n", #exp); throw E_FAIL; } } diff --git a/tests/src/Interop/COM/NativeClients/Dispatch/CoreShim.X.manifest b/tests/src/Interop/COM/NativeClients/Dispatch/CoreShim.X.manifest new file mode 100644 index 0000000000..0e635e03c3 --- /dev/null +++ b/tests/src/Interop/COM/NativeClients/Dispatch/CoreShim.X.manifest @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> + +<assemblyIdentity + type="win32" + name="CoreShim.X" + version="1.0.0.0" /> + +<file name="CoreShim.dll"> + <!-- DispatchTesting --> + <comClass + clsid="{0F8ACD0C-ECE0-4F2A-BD1B-6BFCA93A0726}" + threadingModel="Both" /> +</file> + +</assembly> diff --git a/tests/src/Interop/COM/NativeClients/Primitives/StringTests.cpp b/tests/src/Interop/COM/NativeClients/Primitives/StringTests.cpp index b003130d48..3bef3d7e0b 100644 --- a/tests/src/Interop/COM/NativeClients/Primitives/StringTests.cpp +++ b/tests/src/Interop/COM/NativeClients/Primitives/StringTests.cpp @@ -406,6 +406,32 @@ namespace THROW_FAIL_IF_FALSE(local == actual); } } + + void Marshal_LCID(_In_ IStringTesting* stringTesting) + { + ::printf("Marshal LCIDs\n"); + + HRESULT hr; + + LCID lcid = MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_CHILE), SORT_DEFAULT); + + WStr r = GetReversableStrings<WStr>()[0]; + WStr local{ r }; + + WStr actual; + WStr expected; + THROW_IF_FAILED(r.Reverse(expected)); + + LPWSTR tmp; + THROW_IF_FAILED(stringTesting->Reverse_LPWSTR_With_LCID(local, lcid, &tmp)); + actual.Attach(tmp); + THROW_FAIL_IF_FALSE(expected == actual); + + LCID actualLcid; + + THROW_IF_FAILED(stringTesting->Pass_Through_LCID(lcid, &actualLcid)); + THROW_FAIL_IF_FALSE(lcid == actualLcid); + } } void Run_StringTests() @@ -420,4 +446,5 @@ void Run_StringTests() Marshal_LPString(stringTesting); Marshal_LPWString(stringTesting); Marshal_BStrString(stringTesting); + Marshal_LCID(stringTesting); } diff --git a/tests/src/Interop/COM/NativeServer/DispatchTesting.h b/tests/src/Interop/COM/NativeServer/DispatchTesting.h index 166d6fa749..cf6cefe2d8 100644 --- a/tests/src/Interop/COM/NativeServer/DispatchTesting.h +++ b/tests/src/Interop/COM/NativeServer/DispatchTesting.h @@ -108,6 +108,10 @@ public: // IDispatch { return DoubleHVAValues_Proxy(pDispParams, pVarResult); } + case 6: + { + return PassThroughLCID_Proxy(lcid, pVarResult); + } } return E_NOTIMPL; @@ -410,6 +414,13 @@ private: return DoubleHVAValues(args[0], (HFA_4*)&pVarResult->pvRecord); } + HRESULT PassThroughLCID_Proxy(_In_ LCID lcid, _Inout_ VARIANT* pVarResult) + { + V_VT(pVarResult) = VT_I4; + V_I4(pVarResult) = lcid; + return S_OK; + } + public: // IUnknown STDMETHOD(QueryInterface)( /* [in] */ REFIID riid, @@ -428,7 +439,8 @@ const WCHAR * const DispatchTesting::Names[] = W("Add_Float_ReturnAndUpdateByRef"), W("Add_Double_ReturnAndUpdateByRef"), W("TriggerException"), - W("DoubleHVAValues") + W("DoubleHVAValues"), + W("PassThroughLCID") }; const int DispatchTesting::NamesCount = ARRAYSIZE(DispatchTesting::Names); diff --git a/tests/src/Interop/COM/NativeServer/StringTesting.h b/tests/src/Interop/COM/NativeServer/StringTesting.h index cd01fbe317..1c1f9c1cff 100644 --- a/tests/src/Interop/COM/NativeServer/StringTesting.h +++ b/tests/src/Interop/COM/NativeServer/StringTesting.h @@ -312,6 +312,22 @@ public: // IStringTesting return S_OK; } + DEF_FUNC(Reverse_LPWSTR_With_LCID)( + /*[in]*/ LPWSTR a, + /*[in]*/ LCID lcid, // This parameter is only used as a placeholder to check that we've injected it into the correct arg slot. + /*[out]*/ LPWSTR* b) + { + return Reverse_LPWStr(a, b); + } + + DEF_FUNC(Pass_Through_LCID)( + /*[in]*/ LCID lcidFromCulture, + /*[out]*/ LCID* outLcid) + { + *outLcid = lcidFromCulture; + return S_OK; + } + public: // IUnknown STDMETHOD(QueryInterface)( /* [in] */ REFIID riid, diff --git a/tests/src/Interop/COM/ServerContracts/Server.Contracts.cs b/tests/src/Interop/COM/ServerContracts/Server.Contracts.cs index f16007f38e..89a28a7c68 100644 --- a/tests/src/Interop/COM/ServerContracts/Server.Contracts.cs +++ b/tests/src/Interop/COM/ServerContracts/Server.Contracts.cs @@ -176,6 +176,13 @@ namespace Server.Contract void Reverse_BStr_Out([MarshalAs(UnmanagedType.BStr)] string a, [MarshalAs(UnmanagedType.BStr)] out string b); void Reverse_BStr_OutAttr([MarshalAs(UnmanagedType.BStr)] string a, [Out][MarshalAs(UnmanagedType.BStr)] string b); + + [LCIDConversion(1)] + [return: MarshalAs(UnmanagedType.LPWStr)] + string Reverse_LPWStr_With_LCID([MarshalAs(UnmanagedType.LPWStr)] string a); + + [LCIDConversion(0)] + void Pass_Through_LCID(out int lcid); } public struct HResult @@ -239,6 +246,9 @@ namespace Server.Contract // Special cases HFA_4 DoubleHVAValues(ref HFA_4 input); + + [LCIDConversion(0)] + int PassThroughLCID(); } [ComVisible(true)] diff --git a/tests/src/Interop/COM/ServerContracts/Server.Contracts.h b/tests/src/Interop/COM/ServerContracts/Server.Contracts.h index b2c258d7be..90df20e18e 100644 --- a/tests/src/Interop/COM/ServerContracts/Server.Contracts.h +++ b/tests/src/Interop/COM/ServerContracts/Server.Contracts.h @@ -356,6 +356,13 @@ IStringTesting : IUnknown virtual HRESULT STDMETHODCALLTYPE Reverse_BStr_OutAttr ( /*[in]*/ BSTR a, /*[out]*/ BSTR b ) = 0; + virtual HRESULT STDMETHODCALLTYPE Reverse_LPWSTR_With_LCID ( + /*[in]*/ LPWSTR a, + /*[in]*/ LCID lcid, + /*[out]*/ LPWSTR* b) = 0; + virtual HRESULT STDMETHODCALLTYPE Pass_Through_LCID( + /*[in]*/ LCID lcidFromCulture, + /*[out]*/ LCID* outLcid) = 0; }; struct __declspec(uuid("592386a5-6837-444d-9de3-250815d18556")) diff --git a/tests/src/Interop/PInvoke/Attributes/LCID/LCIDNative.cpp b/tests/src/Interop/PInvoke/Attributes/LCID/LCIDNative.cpp index 77f873553e..028bb466cb 100644 --- a/tests/src/Interop/PInvoke/Attributes/LCID/LCIDNative.cpp +++ b/tests/src/Interop/PInvoke/Attributes/LCID/LCIDNative.cpp @@ -2,119 +2,36 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#include <stdio.h> -#include <tchar.h> -#include <windows.h> #include <xplatform.h> +#include <algorithm> -const char* strManaged = "Managed\0String\0"; -size_t lenstrManaged = 7; // the length of strManaged - -const char* strReturn = "a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; -const char* strFalseReturn = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; - -const char* strNative = " Native\0String\0"; -size_t lenstrNative = 7; //the len of strNative - -extern "C" LPSTR ReturnString() -{ - size_t lenstrReturn = strlen(strReturn); - LPSTR ret = (LPSTR)(CoTaskMemAlloc(sizeof(char)*(lenstrReturn+1))); - memset(ret,'\0',lenstrReturn+1); - strncpy_s(ret,lenstrReturn + 1,strReturn,1); - return ret; -} - -extern "C" LPSTR ReturnFalseString() -{ - size_t lenstrFalseReturn = strlen(strFalseReturn); - LPSTR ret = (LPSTR)(CoTaskMemAlloc(sizeof(char)*(lenstrFalseReturn+1))); - memset(ret,'\0',lenstrFalseReturn+1); - strncpy_s(ret,lenstrFalseReturn + 1,strFalseReturn,1); - return ret; -} - -extern "C" void PrintExpectedAndActual(LPCSTR s, size_t len) +void Reverse(LPCWSTR str, LPWSTR *res) { - //Expected - printf("Expected:"); - for(size_t i = 0; i< lenstrManaged;++i) - putchar(*(((const char *)strManaged)+i)); - printf("\tThe length of Expected:%d\n",static_cast<int>(lenstrManaged)); - - //Actual - printf("Actual:"); - for(size_t j = 0; j < len; ++j ) - putchar(*(((const char *)s) + j)); - printf("\tThe length of Actual:%d\n",static_cast<int>(len)); -} - -extern "C" DLL_EXPORT LPSTR STDMETHODCALLTYPE MarshalStringBuilder_LCID_As_First_Argument(int lcid, LPSTR s) -{ - printf("LCID:%d\n\n",lcid); - - //Check the Input - size_t len = strlen(s); - if((len != lenstrManaged)||(memcmp(s,strManaged,len)!=0)) + LPCWSTR tmp = str; + size_t len = 0; + while (*tmp++) + ++len; + + size_t strDataLen = (len + 1) * sizeof(str[0]); + auto resLocal = (LPWSTR)CoreClrAlloc(strDataLen); + if (resLocal == nullptr) { - printf("Error in Function MarshalStringBuilder_LCID_As_First_Argument(Native Client)\n"); - PrintExpectedAndActual(s, len); - return ReturnFalseString(); + *res = nullptr; + return; } - //In-Place Change - strncpy_s(s,len + 1,strNative,lenstrNative); - - //Return - return ReturnString(); + memcpy(resLocal, str, strDataLen); + + std::reverse(resLocal, resLocal + len); + *res = resLocal; } -extern "C" DLL_EXPORT LPSTR STDMETHODCALLTYPE MarshalStringBuilder_LCID_As_Last_Argument_SetLastError(LPSTR s,int lcid) -{ - //Check the Input - size_t len = strlen(s); - if((len != lenstrManaged)||(memcmp(s,strManaged,len)!=0)) - { - printf("Error in Function MarshalStringBuilder_LCID_As_Last_Argument_SetLastError(Native Client)\n"); - PrintExpectedAndActual(s, len); - return ReturnFalseString(); - } - - //In-Place Change - strncpy_s(s,len + 1,strNative,lenstrNative); - - SetLastError(1090); - //Return - return ReturnString(); +extern "C" void DLL_EXPORT ReverseString(LPCWSTR str, LCID lcid, LPWSTR* reversed) +{ + Reverse(str, reversed); } -extern "C" DLL_EXPORT HRESULT STDMETHODCALLTYPE MarshalStringBuilder_LCID_PreserveSig_SetLastError(LPSTR s, int lcid, LPSTR * retVal) +extern "C" BOOL DLL_EXPORT VerifyValidLCIDPassed(LCID actual, LCID expected) { - //Check the Input - size_t len = strlen(s); - if((len != lenstrManaged)||(memcmp(s,strManaged,len)!=0)) - { - printf("Error in Function MarshalStringBuilder_LCID_PreserveSig_SetLastError\n"); - PrintExpectedAndActual(s, len); - - size_t lenstrFalseReturn = strlen(ReturnFalseString()); - *retVal = (LPSTR)CoTaskMemAlloc(sizeof(char)*(lenstrFalseReturn+1)); - memset(*retVal,'\0',lenstrFalseReturn+1); - strncpy_s(*retVal,lenstrFalseReturn,ReturnFalseString(),lenstrFalseReturn); - - return S_FALSE; - } - - //In-Place Change - strncpy_s(s,len + 1,strNative,lenstrNative); - - //Set the error code. - SetLastError(1090); - - size_t lenstrReturn = strlen(ReturnString()); - *retVal = (LPSTR)(CoTaskMemAlloc(sizeof(char)*(lenstrReturn+1))); - memset(*retVal,'\0',lenstrReturn+1); - strncpy_s(*retVal,lenstrReturn + 1,ReturnString(),lenstrReturn); - - return S_OK; + return actual == expected; } diff --git a/tests/src/Interop/PInvoke/Attributes/LCID/LCIDTest.cs b/tests/src/Interop/PInvoke/Attributes/LCID/LCIDTest.cs index 15c75e9a31..fdf35bbbe0 100644 --- a/tests/src/Interop/PInvoke/Attributes/LCID/LCIDTest.cs +++ b/tests/src/Interop/PInvoke/Attributes/LCID/LCIDTest.cs @@ -2,183 +2,57 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -//The testcase focus test the BStr with embed null string -using System.Runtime.InteropServices; using System; +using System.Globalization; using System.Reflection; +using System.Runtime.InteropServices; using System.Text; +using TestLibrary; -class LCIDTest +class LCIDNative { - [DllImport(@"LCIDNative.dll", EntryPoint = "MarshalStringBuilder_LCID_As_First_Argument")] - [LCIDConversionAttribute(0)] - [return: MarshalAs(UnmanagedType.LPStr)] - private static extern StringBuilder MarshalStringBuilder_LCID_As_First_Argument([In, Out][MarshalAs(UnmanagedType.LPStr)]StringBuilder s); - - [DllImport(@"LCIDNative.dll", EntryPoint = "MarshalStringBuilder_LCID_As_Last_Argument_SetLastError")] - [LCIDConversionAttribute(1)] - [return: MarshalAs(UnmanagedType.LPStr)] - private static extern StringBuilder MarshalStringBuilder_LCID_As_Last_Argument([In, Out][MarshalAs(UnmanagedType.LPStr)]StringBuilder s); - - [DllImport(@"LCIDNative.dll", EntryPoint = "MarshalStringBuilder_LCID_As_Last_Argument_SetLastError", SetLastError = true)] - [LCIDConversionAttribute(1)] - [return: MarshalAs(UnmanagedType.LPStr)] - private static extern StringBuilder MarshalStringBuilder_LCID_As_Last_Argument_SetLastError([In, Out][MarshalAs(UnmanagedType.LPStr)]StringBuilder s); - - [DllImport(@"LCIDNative.dll", EntryPoint = "MarshalStringBuilder_LCID_PreserveSig_SetLastError", PreserveSig = false, SetLastError = true)] - [LCIDConversionAttribute(1)] - [return: MarshalAs(UnmanagedType.LPStr)] - private static extern StringBuilder MarshalStringBuilder_LCID_PreserveSig_SetLastError([In, Out][MarshalAs(UnmanagedType.LPStr)]StringBuilder s); - - //LCID as first argument - static bool Scenario1() - { - Console.WriteLine("Scenairo1 started"); - - string strManaged = "Managed"; - StringBuilder expectedStrRet = new StringBuilder("a", 1); - string strNative = " Native"; - StringBuilder strBNative = new StringBuilder(" Native", 7); - - StringBuilder strPara = new StringBuilder(strManaged, strManaged.Length); - StringBuilder strRet = MarshalStringBuilder_LCID_As_First_Argument(strPara); - - if (expectedStrRet.ToString() != strRet.ToString()) - { - Console.WriteLine("Method MarshalStringBuilder_LCID_As_First_Argument[Managed Side],The Return string is wrong"); - return false; - } - - if (strBNative.ToString() != strPara.ToString()) - { - Console.WriteLine("Method MarshalStringBuilder_LCID_As_First_Argument[Managed Side],The Passed string is wrong"); - return false; - } + [DllImport(nameof(LCIDNative), CharSet = CharSet.Unicode)] + [LCIDConversion(1)] + public static extern void ReverseString(string str, out string result); - Console.WriteLine("Scenairo1 success"); - return true; - } - - //LCID as last argument - static bool Scenario2() - { - Console.WriteLine("Scenairo2 started"); - - string strManaged = "Managed"; - StringBuilder expectedStrRet = new StringBuilder("a", 1); - string strNative = " Native"; - StringBuilder strBNative = new StringBuilder(" Native", 7); - - StringBuilder strPara = new StringBuilder(strManaged, strManaged.Length); - StringBuilder strRet = MarshalStringBuilder_LCID_As_Last_Argument(strPara); - - if (expectedStrRet.ToString() != strRet.ToString()) - { - Console.WriteLine("Method MarshalStringBuilder_LCID_As_Last_Argument[Managed Side],The Return string is wrong"); - return false; - } - - if (strBNative.ToString() != strPara.ToString()) - { - Console.WriteLine("Method MarshalStringBuilder_LCID_As_Last_Argument[Managed Side],The Passed string is wrong"); - return false; - } - - //Verify that error value is set. - int result = Marshal.GetLastWin32Error(); - if (result != 0) - { - Console.WriteLine("MarshalStringBuilder_LCID_As_Last_Argument: GetLasterror returned wrong error code"); - return false; - } - - Console.WriteLine("Scenairo2 success"); - return true; - } - - //SetLastError =true - static bool Scenario3() - { - Console.WriteLine("Scenairo3 started"); - - string strManaged = "Managed"; - StringBuilder expectedStrRet = new StringBuilder("a", 1); - string strNative = " Native"; - StringBuilder strBNative = new StringBuilder(" Native", 7); - - StringBuilder strPara = new StringBuilder(strManaged, strManaged.Length); - StringBuilder strRet = MarshalStringBuilder_LCID_As_Last_Argument_SetLastError(strPara); - - if (expectedStrRet.ToString() != strRet.ToString()) - { - Console.WriteLine("Method MarshalStringBuilder_LCID_As_Last_Argument_SetLastError[Managed Side],The Return string is wrong"); - return false; - } - - if (strBNative.ToString() != strPara.ToString()) - { - Console.WriteLine("Method MarshalStringBuilder_LCID_As_Last_Argument_SetLastError[Managed Side],The Passed string is wrong"); - return false; - } - - //Verify that error value is set. - int result = Marshal.GetLastWin32Error(); - if (result != 1090) - { - Console.WriteLine("MarshalStringBuilder_LCID_As_Last_Argument_SetLastError: GetLasterror returned wrong error code"); - return false; - } - - Console.WriteLine("Scenairo3 success"); - return true; - } + [DllImport(nameof(LCIDNative), CharSet = CharSet.Unicode)] + [LCIDConversion(0)] + public static extern bool VerifyValidLCIDPassed(int lcid); +} - //PreserveSig = false, SetLastError = true - static bool Scenario4() +class LCIDTest +{ + private static string Reverse(string s) { - Console.WriteLine("Scenairo4 started"); - - string strManaged = "Managed"; - StringBuilder expectedStrRet = new StringBuilder("a", 1); - string strNative = " Native"; - StringBuilder strBNative = new StringBuilder(" Native", 7); - - StringBuilder strPara = new StringBuilder(strManaged, strManaged.Length); - StringBuilder strRet = MarshalStringBuilder_LCID_PreserveSig_SetLastError(strPara); - - - if (expectedStrRet.ToString() != strRet.ToString()) - { - Console.WriteLine("Method MarshalStringBuilder_LCID_As_Last_Argument_SetLastError[Managed Side],The Return string is wrong"); - return false; - } - - if (strBNative.ToString() != strPara.ToString()) - { - Console.WriteLine("Method MarshalStringBuilder_LCID_As_Last_Argument_SetLastError[Managed Side],The Passed string is wrong"); - return false; - } - - //Verify that error value is set. - int result = Marshal.GetLastWin32Error(); - if (result != 1090) - { - Console.WriteLine("MarshalStringBuilder_LCID_As_Last_Argument_SetLastError: GetLasterror returned wrong error code"); - return false; - } - - Console.WriteLine("Scenairo4 success"); - return true; + var chars = s.ToCharArray(); + Array.Reverse(chars); + return new string(chars); } - public static int Main(string[] args) + public static int Main() { - var success = true; - success = success && Scenario1(); - success = success && Scenario2(); - success = success && Scenario3(); - success = success && Scenario4(); - - return success ? 100 : 101; + try + { + string testString = "Test string"; + LCIDNative.ReverseString(testString, out string reversed); + Assert.AreEqual(Reverse(testString), reversed); + CultureInfo originalCulture = CultureInfo.CurrentCulture; + try + { + CultureInfo spanishCulture = new CultureInfo("es-ES", false); + CultureInfo.CurrentCulture = spanishCulture; + Assert.IsTrue(LCIDNative.VerifyValidLCIDPassed(CultureInfo.CurrentCulture.LCID)); + } + finally + { + CultureInfo.CurrentCulture = originalCulture; + } + } + catch (System.Exception e) + { + Console.WriteLine(e.ToString()); + return 101; + } + return 100; } } diff --git a/tests/src/Interop/PInvoke/Attributes/LCID/LCIDTest.csproj b/tests/src/Interop/PInvoke/Attributes/LCID/LCIDTest.csproj index 5c446314db..642c209df3 100644 --- a/tests/src/Interop/PInvoke/Attributes/LCID/LCIDTest.csproj +++ b/tests/src/Interop/PInvoke/Attributes/LCID/LCIDTest.csproj @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), Interop.settings.targets))\Interop.settings.targets" /> <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> |