summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Koritzinsky <jekoritz@microsoft.com>2019-05-24 13:20:23 -0700
committerGitHub <noreply@github.com>2019-05-24 13:20:23 -0700
commit73217c884caeca4bcfbb9cc93ffe4c90db79cf7a (patch)
tree45ee95e94186fab0fabe05bd1aa351567daa62ac
parent5894a0f4ecd7360dc25b1e01afb0120efceb7a11 (diff)
downloadcoreclr-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.
-rw-r--r--src/vm/dllimport.cpp9
-rw-r--r--src/vm/interoputil.cpp4
-rw-r--r--src/vm/mscorlib.h2
-rw-r--r--src/vm/threads.cpp21
-rw-r--r--tests/src/Common/Platform/platformdefines.h3
-rw-r--r--tests/src/Interop/CMakeLists.txt1
-rw-r--r--tests/src/Interop/COM/NETClients/IDispatch/Program.cs20
-rw-r--r--tests/src/Interop/COM/NETClients/Primitives/StringTests.cs29
-rw-r--r--tests/src/Interop/COM/NETServer/DispatchTesting.cs79
-rw-r--r--tests/src/Interop/COM/NETServer/StringTesting.cs15
-rw-r--r--tests/src/Interop/COM/NativeClients/Dispatch.csproj24
-rw-r--r--tests/src/Interop/COM/NativeClients/Dispatch/App.manifest17
-rw-r--r--tests/src/Interop/COM/NativeClients/Dispatch/CMakeLists.txt18
-rw-r--r--tests/src/Interop/COM/NativeClients/Dispatch/Client.cpp309
-rw-r--r--tests/src/Interop/COM/NativeClients/Dispatch/ClientTests.h13
-rw-r--r--tests/src/Interop/COM/NativeClients/Dispatch/CoreShim.X.manifest16
-rw-r--r--tests/src/Interop/COM/NativeClients/Primitives/StringTests.cpp27
-rw-r--r--tests/src/Interop/COM/NativeServer/DispatchTesting.h14
-rw-r--r--tests/src/Interop/COM/NativeServer/StringTesting.h16
-rw-r--r--tests/src/Interop/COM/ServerContracts/Server.Contracts.cs10
-rw-r--r--tests/src/Interop/COM/ServerContracts/Server.Contracts.h7
-rw-r--r--tests/src/Interop/PInvoke/Attributes/LCID/LCIDNative.cpp125
-rw-r--r--tests/src/Interop/PInvoke/Attributes/LCID/LCIDTest.cs208
-rw-r--r--tests/src/Interop/PInvoke/Attributes/LCID/LCIDTest.csproj1
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(&params.rgvarg[13]) = VT_UI1;
+ V_UI1(&params.rgvarg[13]) = b1;
+ V_VT(&params.rgvarg[12]) = VT_BYREF | VT_UI1;
+ V_UI1REF(&params.rgvarg[12]) = &b2;
+ V_VT(&params.rgvarg[11]) = VT_I2;
+ V_I2(&params.rgvarg[11]) = s1;
+ V_VT(&params.rgvarg[10]) = VT_BYREF | VT_I2;
+ V_I2REF(&params.rgvarg[10]) = &s2;
+ V_VT(&params.rgvarg[9]) = VT_UI2;
+ V_UI2(&params.rgvarg[9]) = us1;
+ V_VT(&params.rgvarg[8]) = VT_BYREF | VT_UI2;
+ V_UI2REF(&params.rgvarg[8]) = &us2;
+ V_VT(&params.rgvarg[7]) = VT_I4;
+ V_I4(&params.rgvarg[7]) = i1;
+ V_VT(&params.rgvarg[6]) = VT_BYREF | VT_I4;
+ V_I4REF(&params.rgvarg[6]) = &i2;
+ V_VT(&params.rgvarg[5]) = VT_UI4;
+ V_UI4(&params.rgvarg[5]) = ui1;
+ V_VT(&params.rgvarg[4]) = VT_BYREF | VT_UI4;
+ V_UI4REF(&params.rgvarg[4]) = &ui2;
+ V_VT(&params.rgvarg[3]) = VT_I8;
+ V_I8(&params.rgvarg[3]) = l1;
+ V_VT(&params.rgvarg[2]) = VT_BYREF | VT_I8;
+ V_I8REF(&params.rgvarg[2]) = &l2;
+ V_VT(&params.rgvarg[1]) = VT_UI8;
+ V_UI8(&params.rgvarg[1]) = ul1;
+ V_VT(&params.rgvarg[0]) = VT_BYREF | VT_UI8;
+ V_UI8REF(&params.rgvarg[0]) = &ul2;
+
+ THROW_IF_FAILED(dispatchTesting->Invoke(
+ methodId,
+ IID_NULL,
+ lcid,
+ DISPATCH_METHOD,
+ &params,
+ 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(&params.rgvarg[1]) = VT_R4;
+ V_R4(&params.rgvarg[1]) = a;
+ V_VT(&params.rgvarg[0]) = VT_BYREF | VT_R4;
+ V_R4REF(&params.rgvarg[0]) = &b;
+
+
+ THROW_IF_FAILED(dispatchTesting->Invoke(
+ methodId,
+ IID_NULL,
+ lcid,
+ DISPATCH_METHOD,
+ &params,
+ &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(&params.rgvarg[1]) = VT_R8;
+ V_R8(&params.rgvarg[1]) = a;
+ V_VT(&params.rgvarg[0]) = VT_BYREF | VT_R8;
+ V_R8REF(&params.rgvarg[0]) = &b;
+
+
+ THROW_IF_FAILED(dispatchTesting->Invoke(
+ methodId,
+ IID_NULL,
+ lcid,
+ DISPATCH_METHOD,
+ &params,
+ &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,
+ &params,
+ &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>