--- /dev/null
+// 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 <stdio.h>
+#include <tchar.h>
+#include <windows.h>
+#include <xplatform.h>
+
+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)
+{
+ //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))
+ {
+ printf("Error in Function MarshalStringBuilder_LCID_As_First_Argument(Native Client)\n");
+ PrintExpectedAndActual(s, len);
+ return ReturnFalseString();
+ }
+
+ //In-Place Change
+ strncpy_s(s,len + 1,strNative,lenstrNative);
+
+ //Return
+ return ReturnString();
+}
+
+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" DLL_EXPORT HRESULT STDMETHODCALLTYPE MarshalStringBuilder_LCID_PreserveSig_SetLastError(LPSTR s, int lcid, LPSTR * retVal)
+{
+ //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;
+}
--- /dev/null
+// 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.
+
+//The testcase focus test the BStr with embed null string
+using System.Runtime.InteropServices;
+using System;
+using System.Reflection;
+using System.Text;
+
+class LCIDTest
+{
+ [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;
+ }
+
+ 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;
+ }
+
+ //PreserveSig = false, SetLastError = true
+ static bool Scenario4()
+ {
+ 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;
+ }
+
+ public static int Main(string[] args)
+ {
+ var success = true;
+ success = success && Scenario1();
+ success = success && Scenario2();
+ success = success && Scenario3();
+ success = success && Scenario4();
+
+ return success ? 100 : 101;
+ }
+}
--- /dev/null
+<?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>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <AssemblyName>LCIDTest</AssemblyName>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+
+ <!-- Test unsupported outside of windows -->
+ <TestUnsupportedOutsideWindows>true</TestUnsupportedOutsideWindows>
+ <DisableProjectBuild Condition="'$(TargetsUnix)' == 'true'">true</DisableProjectBuild>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'"></PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'"></PropertyGroup>
+ <ItemGroup>
+ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+ <Visible>False</Visible>
+ </CodeAnalysisDependentAssemblyPaths>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="LCIDTest.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="CMakeLists.txt" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>