Add tests for ANSI BSTRs (dotnet/coreclr#20985)
authorJeremy Koritzinsky <jkoritzinsky@gmail.com>
Thu, 15 Nov 2018 22:50:00 +0000 (14:50 -0800)
committerGitHub <noreply@github.com>
Thu, 15 Nov 2018 22:50:00 +0000 (14:50 -0800)
* Add tests for ANSI BSTRs

* Fix signed/unsigned mismatch in comparisons. Add xplatform include

* Use regular memcpy

* Enable ANSI BSTR off-windows.

* Also enable UnmanagedType.TBStr off-Windows since both BStr variants are available off-Windows.

* Make sure the AnsiBSTR marshaller is hooked up off-Windows.

* Remove a few more ifdefs I missed.

* remove ifdefs around binder definitions and the C# stub helpers.

* PR Feedback.

* Add xplat ARRAYSIZE macro

* Move xplat ARRAYSIZE to platformdefines.h

Commit migrated from https://github.com/dotnet/coreclr/commit/97b25b3f1e66b31fbc9f42e8b65aec64710be085

14 files changed:
src/coreclr/src/System.Private.CoreLib/src/System/StubHelpers.cs
src/coreclr/src/vm/ilmarshalers.cpp
src/coreclr/src/vm/ilmarshalers.h
src/coreclr/src/vm/mlinfo.cpp
src/coreclr/src/vm/mscorlib.h
src/coreclr/src/vm/mtypes.h
src/coreclr/tests/src/Common/Platform/platformdefines.h
src/coreclr/tests/src/Interop/CMakeLists.txt
src/coreclr/tests/src/Interop/StringMarshalling/AnsiBSTR/AnsiBStrTest.cs [new file with mode: 0644]
src/coreclr/tests/src/Interop/StringMarshalling/AnsiBSTR/AnsiBStrTest.csproj [new file with mode: 0644]
src/coreclr/tests/src/Interop/StringMarshalling/AnsiBSTR/AnsiBStrTestNative.cpp [new file with mode: 0644]
src/coreclr/tests/src/Interop/StringMarshalling/AnsiBSTR/CMakeLists.txt [new file with mode: 0644]
src/coreclr/tests/src/Interop/StringMarshalling/AnsiBSTR/PinvokeDef.cs [new file with mode: 0644]
src/coreclr/tests/src/Interop/common/xplatform.h

index 9fa2952..aef67a4 100644 (file)
@@ -394,9 +394,6 @@ namespace System.StubHelpers
         }
     }  // class VBByValStrMarshaler
 
-
-#if FEATURE_COMINTEROP
-
     internal static class AnsiBSTRMarshaler
     {
         internal static unsafe IntPtr ConvertToNative(int flags, string strManaged)
@@ -445,9 +442,6 @@ namespace System.StubHelpers
         }
     }  // class AnsiBSTRMarshaler
 
-#endif // FEATURE_COMINTEROP
-
-
     internal static class WSTRBufferMarshaler
     {
         internal static IntPtr ConvertToNative(string strManaged)
index 2dbf5d0..bf0cf3c 100644 (file)
@@ -1879,7 +1879,6 @@ void ILBSTRMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
     EmitStoreManagedValue(pslILEmit);
 }
 
-#ifdef FEATURE_COMINTEROP
 LocalDesc ILAnsiBSTRMarshaler::GetNativeType()
 {
     LIMITED_METHOD_CONTRACT;
@@ -1931,6 +1930,8 @@ void ILAnsiBSTRMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
     pslILEmit->EmitCALL(METHOD__ANSIBSTRMARSHALER__CLEAR_NATIVE, 1, 0);
 }
 
+#ifdef FEATURE_COMINTEROP
+
 LocalDesc ILHSTRINGMarshaler::GetNativeType()
 {
     LIMITED_METHOD_CONTRACT;
index 0767fb8..6a67bf6 100644 (file)
@@ -2647,7 +2647,6 @@ protected:
     virtual void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit);
 };
 
-#ifdef FEATURE_COMINTEROP
 class ILAnsiBSTRMarshaler : public ILMarshaler
 {
 public:
@@ -2666,7 +2665,6 @@ protected:
     virtual bool NeedsClearNative();
     virtual void EmitClearNative(ILCodeStream* pslILEmit);
 };
-#endif // FEATURE_COMINTEROP
 
 class ILLayoutClassPtrMarshalerBase : public ILMarshaler
 {
index f7fc265..43b39d1 100644 (file)
@@ -2133,7 +2133,7 @@ MarshalInfo::MarshalInfo(Module* pModule,
                             }
                             m_type = MARSHAL_TYPE_BSTR;
                             break;
-#ifdef FEATURE_COMINTEROP     
+
                         case NATIVE_TYPE_ANSIBSTR:
                             if (builder)
                             {
@@ -2142,7 +2142,7 @@ MarshalInfo::MarshalInfo(Module* pModule,
                             }
                             m_type = MARSHAL_TYPE_ANSIBSTR;
                             break;
-                           
+                            
                         case NATIVE_TYPE_TBSTR:
                         {
                             if (builder)
@@ -2156,6 +2156,7 @@ MarshalInfo::MarshalInfo(Module* pModule,
                             break;
                         }
 
+#ifdef FEATURE_COMINTEROP
                         case NATIVE_TYPE_BYVALSTR:
                         {
                             if (builder)
index 3cabfc8..b2eb63b 100644 (file)
@@ -1079,12 +1079,12 @@ DEFINE_METHOD(BSTRMARSHALER,        CONVERT_TO_NATIVE,      ConvertToNative,
 DEFINE_METHOD(BSTRMARSHALER,        CONVERT_TO_MANAGED,     ConvertToManaged,           SM_IntPtr_RetStr)
 DEFINE_METHOD(BSTRMARSHALER,        CLEAR_NATIVE,           ClearNative,                SM_IntPtr_RetVoid)
 
-#ifdef FEATURE_COMINTEROP
 DEFINE_CLASS(ANSIBSTRMARSHALER,     StubHelpers,            AnsiBSTRMarshaler)
 DEFINE_METHOD(ANSIBSTRMARSHALER,    CONVERT_TO_NATIVE,      ConvertToNative,            SM_Int_Str_RetIntPtr)
 DEFINE_METHOD(ANSIBSTRMARSHALER,    CONVERT_TO_MANAGED,     ConvertToManaged,           SM_IntPtr_RetStr)
 DEFINE_METHOD(ANSIBSTRMARSHALER,    CLEAR_NATIVE,           ClearNative,                SM_IntPtr_RetVoid)
 
+#ifdef FEATURE_COMINTEROP
 DEFINE_CLASS(OBJECTMARSHALER,       StubHelpers,            ObjectMarshaler)
 DEFINE_METHOD(OBJECTMARSHALER,      CONVERT_TO_NATIVE,      ConvertToNative,            SM_ObjIntPtr_RetVoid)
 DEFINE_METHOD(OBJECTMARSHALER,      CONVERT_TO_MANAGED,     ConvertToManaged,           SM_IntPtr_RetObj)
index f31ba1f..af21d26 100644 (file)
@@ -43,8 +43,8 @@ DEFINE_MARSHALER_TYPE(MARSHAL_TYPE_LPWSTR,          WSTRMarshaler,
 DEFINE_MARSHALER_TYPE(MARSHAL_TYPE_LPSTR,           CSTRMarshaler,                       false)
 DEFINE_MARSHALER_TYPE(MARSHAL_TYPE_LPUTF8STR,       CUTF8Marshaler,                      false)
 DEFINE_MARSHALER_TYPE(MARSHAL_TYPE_BSTR,            BSTRMarshaler,                       false)
-#ifdef FEATURE_COMINTEROP
 DEFINE_MARSHALER_TYPE(MARSHAL_TYPE_ANSIBSTR,        AnsiBSTRMarshaler,                   false)
+#ifdef FEATURE_COMINTEROP
 DEFINE_MARSHALER_TYPE(MARSHAL_TYPE_HSTRING,         HSTRINGMarshaler,                    true)
 DEFINE_MARSHALER_TYPE(MARSHAL_TYPE_DATETIME,        DateTimeMarshaler,                   true)
 DEFINE_MARSHALER_TYPE(MARSHAL_TYPE_URI,             UriMarshaler,                        true)
index 498c438..1cc334c 100644 (file)
@@ -59,6 +59,8 @@ typedef unsigned long ULONG, *PULONG;
 #define E_INVALIDARG                     _HRESULT_TYPEDEF_(0x80070057L)
 #define UInt32x32To64(a, b) ((unsigned __int64)((ULONG)(a)) * (unsigned __int64)((ULONG)(b)))
 
+#define ARRAYSIZE(x) (sizeof(x)/sizeof(*x))
+
 #ifndef TRUE
 #define TRUE 1
 #endif
@@ -141,7 +143,7 @@ void TP_DebugBreak();
 DWORD TP_GetFullPathName(LPWSTR fileName, DWORD nBufferLength, LPWSTR lpBuffer);
 
 typedef WCHAR* BSTR;
-BSTR TP_SysAllocStringByteLen(LPSTR psz, size_t len);
+BSTR TP_SysAllocStringByteLen(LPCSTR psz, size_t len);
 void TP_SysFreeString(BSTR bstr);
 size_t TP_SysStringByteLen(BSTR bstr);
 BSTR TP_SysAllocStringLen(LPWSTR psz, size_t len);
index c509665..cab63b7 100644 (file)
@@ -41,6 +41,7 @@ add_subdirectory(StringMarshalling/LPSTR)
 add_subdirectory(StringMarshalling/LPTSTR)
 add_subdirectory(StringMarshalling/UTF8)
 add_subdirectory(StringMarshalling/BSTR)
+add_subdirectory(StringMarshalling/AnsiBSTR)
 add_subdirectory(MarshalAPI/FunctionPointer)
 add_subdirectory(MarshalAPI/IUnknown)
 add_subdirectory(SizeConst)
diff --git a/src/coreclr/tests/src/Interop/StringMarshalling/AnsiBSTR/AnsiBStrTest.cs b/src/coreclr/tests/src/Interop/StringMarshalling/AnsiBSTR/AnsiBStrTest.cs
new file mode 100644 (file)
index 0000000..5fa0ede
--- /dev/null
@@ -0,0 +1,111 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using System;
+using System.Reflection;
+using System.Text;
+using NativeDefs;
+using System.Diagnostics;
+
+class Test
+{
+
+    #region "Report Failure"
+    static int fails = 0; //record the fail numbers
+    // Overload methods for reportfailure
+    static int ReportFailure(string s)
+    {
+        Console.WriteLine(" === Fail:" + s);
+        return (++fails);
+    }
+    static int ReportFailure(string expect, string actual)
+    {
+        Console.WriteLine(" === Fail: Expected:" + expect + "\n          Actual:" + actual);
+        return (++fails);
+    }
+    static int ReportFailure(string describe, string expect, string actual)
+    {
+        Console.WriteLine(" === Fail: " + describe + "\n\tExpected:" + expect + "\n\tActual:" + actual);
+        return (++fails);
+    }
+    #endregion
+
+    #region "Helper"
+    // ************************************************************
+    // Returns the appropriate exit code
+    // *************************************************************
+    static int ExitTest()
+    {
+        if (fails == 0)
+        {
+            Console.WriteLine("PASS");
+            return 100;
+        }
+        else
+        {
+            Console.WriteLine("FAIL - " + fails + " failure(s) occurred");
+            return 101;
+        }
+    }
+    #endregion
+
+    public static int Main(string[] args)
+    {
+        string strManaged = " \0Managed\0String\0 ";
+        string strRet = "a";
+        string strNative = "Native String";
+
+        //since the out attributes doesnt work for string, so i dont check the out value.
+        string strPara2 = strManaged;
+        string strRet2 = AnsiBStrTestNative.Marshal_InOut(strPara2);
+        if (!strRet2.Equals(strRet))
+        {
+            ReportFailure("Method AnsiBStrTestNative.Marshal_InOut[Managed Side],The Return string is wrong", strRet, strRet2);
+        }
+        if (!strPara2.Equals(strManaged))
+        {
+            ReportFailure("Method AnsiBStrTestNative.Marshal_InOut[Managed Side],The Parameter string is Changed", strManaged, strPara2);
+        }
+
+        //TestMethod3
+        string strPara3 = strManaged;
+        string strRet3 = AnsiBStrTestNative.Marshal_Out(strPara3);
+        if (!strRet.Equals(strRet3))
+        {
+            ReportFailure("Method AnsiBStrTestNative.Marshal_Out[Managed Side],The Return string is wrong", strRet, strRet3);
+        }
+        if (!strPara3.Equals(strManaged))
+        {
+            ReportFailure("Method AnsiBStrTestNative.Marshal_Out[Managed Side],The Parameter string is not Changed", strManaged, strPara3);
+        }
+
+        //TestMethod5
+        string strPara5 = strManaged;
+        string strRet5 = AnsiBStrTestNative.MarshalPointer_InOut(ref strPara5);
+
+        if (!strRet5.Equals(strRet))
+        {
+            ReportFailure("Method AnsiBStrTestNative.MarshalPointer_InOut[Managed Side],The Return string is wrong", strRet, strRet5);
+        }
+        if (!strPara5.Equals(strNative))
+        {
+            ReportFailure("Method AnsiBStrTestNative.MarshalPointer_InOut[Managed Side],The Passed string is wrong", strNative, strPara5);
+        }
+
+        //TestMethod6
+        string strPara6 = strManaged;
+        string strRet6 = AnsiBStrTestNative.MarshalPointer_Out(out strPara6);
+        if (!strRet6.Equals(strRet))
+        {
+            ReportFailure("Method AnsiBStrTestNative.MarshalPointer_Out[Managed Side],The Return string is wrong", strRet, strRet6);
+        }
+        if (!strPara6.Equals(strNative))
+        {
+            ReportFailure("Method AnsiBStrTestNative.MarshalPointer_Out[Managed Side],The Passed string is wrong", strNative, strPara6);
+        }
+
+        return ExitTest();
+    }
+}
diff --git a/src/coreclr/tests/src/Interop/StringMarshalling/AnsiBSTR/AnsiBStrTest.csproj b/src/coreclr/tests/src/Interop/StringMarshalling/AnsiBSTR/AnsiBStrTest.csproj
new file mode 100644 (file)
index 0000000..744f09d
--- /dev/null
@@ -0,0 +1,41 @@
+<?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>AnsiBStrTest</AssemblyName>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{176EC495-7AE9-42CF-A591-06A382DB4048}</ProjectGuid>
+    <OutputType>exe</OutputType>
+    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>  
+    <DefineConstants>$(DefineConstants);STATIC</DefineConstants>
+  </PropertyGroup>
+  <!-- Default configurations to help VS understand the configurations -->
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+  </PropertyGroup>
+  <ItemGroup>
+    <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+      <Visible>False</Visible>
+    </CodeAnalysisDependentAssemblyPaths>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="*.cs" />    
+  </ItemGroup>
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\Common\CoreCLRTestLibrary\CoreCLRTestLibrary.csproj">
+      <Project>{c8c0dc74-fac4-45b1-81fe-70c4808366e0}</Project>
+      <Name>CoreCLRTestLibrary</Name>
+    </ProjectReference>
+    <ProjectReference Include="CMakeLists.txt">
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/src/coreclr/tests/src/Interop/StringMarshalling/AnsiBSTR/AnsiBStrTestNative.cpp b/src/coreclr/tests/src/Interop/StringMarshalling/AnsiBSTR/AnsiBStrTestNative.cpp
new file mode 100644 (file)
index 0000000..ca9d92c
--- /dev/null
@@ -0,0 +1,142 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+#include <xplatform.h>
+#include "platformdefines.h"
+
+const char strManaged[] = " \0Managed\0String\0 ";
+size_t lenstrManaged = ARRAYSIZE(strManaged) - 1; // the length of strManaged
+
+const char strReturn[] = "a";
+size_t lenstrReturn = ARRAYSIZE(strReturn) - 1; //the length of strReturn
+
+const char strNative[] = "Native String";
+size_t lenstrNative = ARRAYSIZE(strNative) - 1; //the len of strNative
+
+//Test Method1
+extern "C" DLL_EXPORT BSTR STDMETHODCALLTYPE Marshal_In(/*[in]*/ BSTR s)
+{
+    //Check the input
+    size_t len = TP_SysStringByteLen(s);
+    if ((len != lenstrManaged) || (memcmp(s, strManaged, len) != 0))
+    {
+        printf("Error in Function Marshal_In(Native Client)\n");
+
+        //Expected
+        printf("Expected:");
+        for (size_t i = 0; i < lenstrManaged; ++i)
+            putchar(*(((char *)strManaged) + i));
+        printf("\tThe length of Expected:%zd\n", lenstrManaged);
+
+        //Actual
+        printf("Actual:");
+        for (size_t j = 0; j < len; ++j)
+            putchar(*(((char *)s) + j));
+        printf("\tThe length of Actual:%zd\n", len);
+    }
+
+    return TP_SysAllocStringByteLen(strReturn, lenstrReturn);
+}
+
+//Test Method2
+extern "C" DLL_EXPORT BSTR STDMETHODCALLTYPE Marshal_InOut(/*[In,Out]*/ BSTR s)
+{
+
+    //Check the Input
+    size_t len = TP_SysStringByteLen(s);
+    if ((len != lenstrManaged) || (memcmp(s, strManaged, len) != 0))
+    {
+        printf("Error in Function Marshal_InOut(Native Client)\n");
+
+        //Expected
+        printf("Expected:");
+        for (size_t i = 0; i < lenstrManaged; ++i)
+            putchar(*(((char *)strManaged) + i));
+        printf("\tThe length of Expected:%zd\n", lenstrManaged);
+
+        //Actual
+        printf("Actual:");
+        for (size_t j = 0; j < len; ++j)
+            putchar(*(((char *)s) + j));
+        printf("\tThe length of Actual:%zd\n", len);
+    }
+
+    //In-Place Change
+    memcpy((char *)s, strNative, lenstrNative);
+    *((UINT *)s - 1) = (UINT) TP_SysStringByteLen(s);
+
+    //Return
+    return TP_SysAllocStringByteLen(strReturn, lenstrReturn);
+}
+extern "C" DLL_EXPORT BSTR STDMETHODCALLTYPE Marshal_Out(/*[Out]*/ BSTR s)
+{
+    s = TP_SysAllocStringByteLen(strNative, lenstrNative);
+
+    //In-Place Change
+    memcpy((char *)s, strNative, lenstrNative);
+    *((UINT *)s - 1) = (UINT) TP_SysStringByteLen(s);
+
+    //Return
+    return TP_SysAllocStringByteLen(strReturn, lenstrReturn);
+}
+
+extern "C" DLL_EXPORT BSTR STDMETHODCALLTYPE MarshalPointer_In(/*[in]*/ BSTR *s)
+{
+    //CheckInput
+    size_t len = TP_SysStringByteLen(*s);
+    if ((len != lenstrManaged) || (memcmp(*s, strManaged, len) != 0))
+    {
+        printf("Error in Function MarshalPointer_In\n");
+
+        //Expected
+        printf("Expected:");
+        for (size_t i = 0; i < lenstrManaged; ++i)
+            putchar(*(((char *)strManaged) + i));
+        printf("\tThe length of Expected:%zd\n", lenstrManaged);
+
+        //Actual
+        printf("Actual:");
+        for (size_t j = 0; j < len; ++j)
+            putchar(*(((char *)*s) + j));
+        printf("\tThe length of Actual:%zd\n", len);
+    }
+
+    return TP_SysAllocStringByteLen(strReturn, lenstrReturn);
+}
+
+extern "C" DLL_EXPORT BSTR STDMETHODCALLTYPE MarshalPointer_InOut(/*[in,out]*/ BSTR *s)
+{
+    //Check the Input
+    size_t len = TP_SysStringByteLen(*s);
+    if ((len != lenstrManaged) || (memcmp(*s, strManaged, len) != 0))
+    {
+        printf("Error in Function MarshalPointer_InOut\n");
+
+        //Expected
+        printf("Expected:");
+        for (size_t i = 0; i < lenstrManaged; ++i)
+            putchar(*(((char *)strManaged) + i));
+
+        printf("\tThe length of Expected:%zd\n", lenstrManaged);
+
+        //Actual
+        printf("Actual:");
+        for (size_t j = 0; j < len; ++j)
+            putchar(*(((char *)*s) + j));
+
+        printf("\tThe length of Actual:%zd\n", len);
+    }
+
+    //Allocate New
+    TP_SysFreeString(*s);
+    *s = TP_SysAllocStringByteLen(strNative, lenstrNative);
+
+    //Return
+    return TP_SysAllocStringByteLen(strReturn, lenstrReturn);
+}
+
+extern "C" DLL_EXPORT BSTR STDMETHODCALLTYPE MarshalPointer_Out(/*[out]*/ BSTR *s)
+{
+    *s = TP_SysAllocStringByteLen(strNative, lenstrNative);
+    return TP_SysAllocStringByteLen(strReturn, lenstrReturn);
+}
diff --git a/src/coreclr/tests/src/Interop/StringMarshalling/AnsiBSTR/CMakeLists.txt b/src/coreclr/tests/src/Interop/StringMarshalling/AnsiBSTR/CMakeLists.txt
new file mode 100644 (file)
index 0000000..2bf1435
--- /dev/null
@@ -0,0 +1,18 @@
+cmake_minimum_required (VERSION 2.6)
+project (AnsiBStrTestNative)
+include_directories(${INC_PLATFORM_DIR})
+set(SOURCES AnsiBStrTestNative.cpp)
+
+# add the executable
+add_library (AnsiBStrTestNative SHARED ${SOURCES})
+
+if(WIN32)
+    list(APPEND LINK_LIBRARIES_ADDITIONAL
+        OleAut32.lib
+    )
+endif(WIN32)
+
+target_link_libraries(AnsiBStrTestNative ${LINK_LIBRARIES_ADDITIONAL}) 
+
+# add the install targets
+install (TARGETS AnsiBStrTestNative DESTINATION bin)
diff --git a/src/coreclr/tests/src/Interop/StringMarshalling/AnsiBSTR/PinvokeDef.cs b/src/coreclr/tests/src/Interop/StringMarshalling/AnsiBSTR/PinvokeDef.cs
new file mode 100644 (file)
index 0000000..b77667d
--- /dev/null
@@ -0,0 +1,34 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using System;
+using System.Reflection;
+using System.Text;
+
+#pragma warning disable CS0618
+
+namespace NativeDefs
+{
+    public static class AnsiBStrTestNative
+    {
+        public const string NativeBinaryName = nameof(AnsiBStrTestNative);
+
+        [DllImport(NativeBinaryName)]
+        [return: MarshalAs(UnmanagedType.AnsiBStr)]
+        public static extern string Marshal_InOut([In, Out][MarshalAs(UnmanagedType.AnsiBStr)]string s);
+
+        [DllImport(NativeBinaryName)]
+        [return: MarshalAs(UnmanagedType.AnsiBStr)]
+        public static extern string Marshal_Out([Out][MarshalAs(UnmanagedType.AnsiBStr)]string s);
+
+        [DllImport(NativeBinaryName)]
+        [return: MarshalAs(UnmanagedType.AnsiBStr)]
+        public static extern string MarshalPointer_InOut([MarshalAs(UnmanagedType.AnsiBStr)]ref string s);
+
+        [DllImport(NativeBinaryName)]
+        [return: MarshalAs(UnmanagedType.AnsiBStr)]
+        public static extern string MarshalPointer_Out([MarshalAs(UnmanagedType.AnsiBStr)]out string s);
+    }
+}