Marshaling helpers for MarshalAs LPUTF8Str.
authortijoytk <tijoytk@microsoft.com>
Wed, 11 May 2016 17:00:52 +0000 (10:00 -0700)
committertijoytk <tijoytk@microsoft.com>
Thu, 12 May 2016 21:42:24 +0000 (14:42 -0700)
src/mscorlib/model.xml
src/mscorlib/src/System/Runtime/InteropServices/Marshal.cs
tests/src/Interop/MarshalAPI/String/StringMarshalingTest.cs
tests/src/Interop/MarshalAPI/String/StringMarshalingTest.csproj
tests/src/Interop/MarshalAPI/String/project.json
tests/src/Interop/StringMarshalling/UTF8/UTF8TestNative.cpp

index 28ba1a6..1dc26fc 100644 (file)
       <Member Name="PrelinkAll(System.Type)" />
       <Member Name="PtrToStringAnsi(System.IntPtr)" />
       <Member Name="PtrToStringAnsi(System.IntPtr,System.Int32)" />
+      <Member Name="PtrToStringUTF8(System.IntPtr)" />
+      <Member Name="PtrToStringUTF8(System.IntPtr,System.Int32)" />
       <Member Name="PtrToStringUni(System.IntPtr)" />
       <Member Name="PtrToStringUni(System.IntPtr,System.Int32)" />
       <Member Name="PtrToStructure(System.IntPtr,System.Object)" />
       <Member Name="StringToCoTaskMemUni(System.String)" />
       <Member Name="StringToHGlobalAnsi(System.String)" />
       <Member Name="StringToHGlobalUni(System.String)" />
+      <Member Name="StringToAllocatedMemoryUTF8(System.String)" />
       <Member Name="StructureToPtr&lt;T&gt;(T,System.IntPtr,System.Boolean)" />
       <Member Name="UnsafeAddrOfPinnedArrayElement&lt;T&gt;(T[],System.Int32)" />
       <Member Name="WriteByte(System.Object,System.Int32,System.Byte)" />
       <Member Name="ZeroFreeCoTaskMemAnsi(System.IntPtr)" />
       <Member Name="ZeroFreeGlobalAllocAnsi(System.IntPtr)" />
       <Member Name="ZeroFreeGlobalAllocUnicode(System.IntPtr)" />
+      <Member Name="ZeroFreeMemoryUTF8(System.IntPtr)" />
     </Type>
     <Type Name="System.Runtime.InteropServices.MarshalAsAttribute">
       <Member MemberType="Field" Name="ArraySubType" />
index 945c4f7..2423d37 100644 (file)
@@ -116,7 +116,7 @@ namespace System.Runtime.InteropServices
         //====================================================================
         [MethodImplAttribute(MethodImplOptions.InternalCall)]
         private static extern int GetSystemMaxDBCSCharSize();
-
+        
         [System.Security.SecurityCritical]  // auto-generated_required
         unsafe public static String PtrToStringAnsi(IntPtr ptr)
         {
@@ -185,7 +185,40 @@ namespace System.Runtime.InteropServices
         {
             // Ansi platforms are no longer supported
             return PtrToStringUni(ptr);
-        }            
+        }
+
+        [System.Security.SecurityCritical]  // auto-generated_required
+        unsafe public static String PtrToStringUTF8(IntPtr ptr)
+        {
+            int nbBytes = System.StubHelpers.StubHelpers.strlen((sbyte*)ptr.ToPointer());
+            return PtrToStringUTF8(ptr, nbBytes);
+        }
+
+        [System.Security.SecurityCritical]  // auto-generated_required
+        unsafe public static String PtrToStringUTF8(IntPtr ptr,int byteLen)
+        {
+            if (byteLen < 0)
+            {
+                throw new ArgumentException("len");
+            }
+            else if (IntPtr.Zero == ptr)
+            {
+                return null;
+            }
+            else if (IsWin32Atom(ptr))
+            {
+                return null;
+            }
+            else if (byteLen == 0)
+            {
+                return string.Empty;
+            }
+            else
+            {
+                byte* pByte = (byte*)ptr.ToPointer();
+                return Encoding.UTF8.GetString(pByte, byteLen);
+            }
+        }
 
         //====================================================================
         // SizeOf()
@@ -1060,7 +1093,7 @@ namespace System.Runtime.InteropServices
             }
 
             if (rtModule == null)
-                throw new ArgumentNullException("m", Environment.GetResourceString("Argument_MustBeRuntimeModule"));
+                throw new ArgumentNullException(Environment.GetResourceString("Argument_MustBeRuntimeModule"));
 
             return GetHINSTANCE(rtModule.GetNativeHandle());
         }    
@@ -1872,6 +1905,38 @@ namespace System.Runtime.InteropServices
         }
 
         [System.Security.SecurityCritical]  // auto-generated_required
+        unsafe public static IntPtr StringToAllocatedMemoryUTF8(String s)
+        {
+            const int MAX_UTF8_CHAR_SIZE = 3;
+            if (s == null)
+            {
+                return IntPtr.Zero;
+            }
+            else
+            {
+                int nb = (s.Length + 1) * MAX_UTF8_CHAR_SIZE;
+
+                // Overflow checking
+                if (nb < s.Length)
+                    throw new ArgumentOutOfRangeException("s");
+
+                IntPtr pMem = Win32Native.CoTaskMemAlloc(new UIntPtr((uint)nb +1));
+
+                if (pMem == IntPtr.Zero)
+                {
+                    throw new OutOfMemoryException();
+                }
+                else
+                {
+                    byte* pbMem = (byte*)pMem;
+                    int nbWritten = s.GetBytesFromEncoding(pbMem, nb, Encoding.UTF8);
+                    pbMem[nbWritten] = 0;
+                    return pMem;
+                }
+            }
+        }
+
+        [System.Security.SecurityCritical]  // auto-generated_required
         public static IntPtr StringToCoTaskMemAuto(String s)
         {
             // Ansi platforms are no longer supported
@@ -2659,6 +2724,13 @@ namespace System.Runtime.InteropServices
             FreeCoTaskMem(s);
         }
 
+        [System.Security.SecurityCritical]  // auto-generated_required
+        unsafe public static void ZeroFreeMemoryUTF8(IntPtr s)
+        {
+            Win32Native.ZeroMemory(s, (UIntPtr)System.StubHelpers.StubHelpers.strlen((sbyte*)s));
+            FreeCoTaskMem(s);
+        }
+
 #if FEATURE_LEGACYSURFACE
         [System.Security.SecurityCritical]  // auto-generated_required
         public static IntPtr SecureStringToGlobalAllocAnsi(SecureString s) {
index f4ec24f..4f5fbf2 100644 (file)
@@ -171,6 +171,32 @@ public class StringMarshalingTest
 
     }
 
+    public  void TestUTF8String()
+    {
+        foreach (String srcString in TestStrings)
+        {
+            // we assume string null terminated
+            if (srcString.Contains("\0"))
+                continue;
+
+            IntPtr ptrString = Marshal.StringToAllocatedMemoryUTF8(srcString);
+            string retString = Marshal.PtrToStringUTF8(ptrString);
+
+            if (!srcString.Equals(retString))
+            {
+                throw new Exception("Round triped strings do not match...");
+            }
+            if (srcString.Length > 0)
+            {
+                string retString2 = Marshal.PtrToStringUTF8(ptrString, srcString.Length - 1);
+                if (!retString2.Equals(srcString.Substring(0, srcString.Length - 1)))
+                {
+                    throw new Exception("Round triped strings do not match...");
+                }
+            }
+            Marshal.FreeHGlobal(ptrString);
+        }
+    }
 
     public  bool RunTests()
     {
@@ -179,6 +205,7 @@ public class StringMarshalingTest
         StringToCoTaskMemUniToString();
         StringToHGlobalAnsiToString();
         StringToHGlobalUniToString();
+        TestUTF8String();
         return true;
     }
 
index 9e3b782..d4528a5 100644 (file)
@@ -7,15 +7,16 @@
     <AssemblyName>StringMarshalingTest</AssemblyName>
     <SchemaVersion>2.0</SchemaVersion>
     <ProjectGuid>{F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0}</ProjectGuid>
-    <OutputType>Exe</OutputType>
+    <OutputType>exe</OutputType>
     <AppDesignerFolder>Properties</AppDesignerFolder>
     <FileAlignment>512</FileAlignment>
     <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
     <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages</ReferencePath>
     <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
-
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>  
     <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
     <DefineConstants>$(DefineConstants);STATIC</DefineConstants>
+    <ReferenceLocalMscorlib>true</ReferenceLocalMscorlib>
   </PropertyGroup>
   <!-- Default configurations to help VS understand the configurations -->
   <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
@@ -28,8 +29,8 @@
     </CodeAnalysisDependentAssemblyPaths>
   </ItemGroup>
   <ItemGroup>
-    <Compile Include="*.cs" />
-    <Compile Include="..\..\Common\Assertion.cs" />
+    <Compile Include="*.cs" />    
+    <Compile Include="..\..\common\Assertion.cs" />    
   </ItemGroup>
   <ItemGroup>
     <None Include="project.json" />
@@ -41,7 +42,7 @@
     <ProjectReference Include="..\..\..\Common\CoreCLRTestLibrary\CoreCLRTestLibrary.csproj">
       <Project>{c8c0dc74-fac4-45b1-81fe-70c4808366e0}</Project>
       <Name>CoreCLRTestLibrary</Name>
-    </ProjectReference>    
+    </ProjectReference>   
   </ItemGroup>
   <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project>
+</Project>
\ No newline at end of file
index fc8ccb4..fc3f026 100644 (file)
@@ -1,34 +1,5 @@
 {
-  "dependencies": {
-    "Microsoft.NETCore.Platforms": "1.0.1-rc2-23816",
-    "System.Collections": "4.0.10",
-    "System.Collections.NonGeneric": "4.0.1-rc2-23816",
-    "System.Collections.Specialized": "4.0.1-rc2-23816",
-    "System.ComponentModel": "4.0.1-rc2-23816",
-    "System.Console": "4.0.0-rc2-23816",
-    "System.Diagnostics.Process": "4.1.0-rc2-23816",
-    "System.Globalization": "4.0.10",
-    "System.Globalization.Calendars": "4.0.0",
-    "System.IO": "4.0.10",
-    "System.IO.FileSystem": "4.0.0",
-    "System.IO.FileSystem.Primitives": "4.0.0",
-    "System.Linq": "4.0.1-rc2-23816",
-    "System.Linq.Queryable": "4.0.1-rc2-23816",
-    "System.Reflection": "4.0.10",
-    "System.Reflection.Primitives": "4.0.0",
-    "System.Runtime": "4.1.0-rc2-23816",
-    "System.Runtime.Extensions": "4.0.10",
-    "System.Runtime.Handles": "4.0.0",
-    "System.Runtime.InteropServices": "4.1.0-rc2-23816",
-    "System.Runtime.Loader": "4.0.0-rc2-23816",
-    "System.Text.Encoding": "4.0.10",
-    "System.Threading": "4.0.10",
-    "System.Threading.Thread": "4.0.0-rc2-23816",
-    "System.Xml.ReaderWriter": "4.0.11-rc2-23816",
-    "System.Xml.XDocument": "4.0.11-rc2-23816",
-    "System.Xml.XmlDocument": "4.0.1-rc2-23816",
-    "System.Xml.XmlSerializer": "4.0.11-rc2-23816"
-  },
+  "dependencies": {},
   "frameworks": {
     "dnxcore50": {}
   },
index 77e4b9c..f4e0f2f 100644 (file)
@@ -4,34 +4,43 @@
 
 #include <xplatform.h>
 
-// helper functions
-#ifdef _WIN32  
-char* UTF16ToUTF8(wchar_t * pszTextUTF16)
+const int NSTRINGS = 6;
+#ifdef _WIN32
+wchar_t  *utf8strings[] = { L"Managed",
+L"S\x00EEne kl\x00E2wen durh die wolken sint geslagen" ,
+L"\x0915\x093E\x091A\x0902 \x0936\x0915\x094D\x0928\x094B\x092E\x094D\x092F\x0924\x094D\x0924\x0941\x092E\x094D \x0964 \x0928\x094B\x092A\x0939\x093F\x0928\x0938\x094D\x0924\x093F \x092E\x093E\x092E\x094D",
+L"\x6211\x80FD\x541E\x4E0B\x73BB\x7483\x800C\x4E0D\x4F24\x8EAB\x4F53",
+L"\x10E6\x10DB\x10D4\x10E0\x10D7\x10E1\x10D8 \x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4,\x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4, \x10DC\x10E3\x10D7\x10E3 \x10D9\x10D5\x10DA\x10D0 \x10D3\x10D0\x10DB\x10EE\x10E1\x10DC\x10D0\x10E1 \x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4,\x10E1\x10DD\x10E4\x10DA\x10D8\x10E1\x10D0 \x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4, \x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4,\x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4,\x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4,\x10E8\x10E0\x10DD\x10DB\x10D0\x10E1\x10D0, \x10EA\x10D4\x10EA\x10EE\x10DA\x10E1, \x10EC\x10E7\x10D0\x10DA\x10E1\x10D0 \x10D3\x10D0 \x10DB\x10D8\x10EC\x10D0\x10E1\x10D0, \x10F0\x10D0\x10D4\x10E0\x10D7\x10D0 \x10D7\x10D0\x10DC\x10D0 \x10DB\x10E0\x10DD\x10DB\x10D0\x10E1\x10D0; \x10DB\x10DD\x10DB\x10EA\x10DC\x10D4\x10E1 \x10E4\x10E0\x10D7\x10D4\x10DC\x10D8 \x10D3\x10D0 \x10D0\x10E6\x10D5\x10E4\x10E0\x10D8\x10DC\x10D3\x10D4, \x10DB\x10D8\x10D5\x10F0\x10EE\x10D5\x10D3\x10D4 \x10DB\x10D0\x10E1 \x10E9\x10D4\x10DB\x10E1\x10D0 \x10DC\x10D3\x10DD\x10DB\x10D0\x10E1\x10D0, \x10D3\x10E6\x10D8\x10E1\x10D8\x10D7 \x10D3\x10D0 \x10E6\x10D0\x10DB\x10D8\x10D7 \x10D5\x10F0\x10EE\x10D4\x10D3\x10D5\x10D8\x10D3\x10D4 \x10DB\x10D6\x10D8\x10E1\x10D0 \x10D4\x10DA\x10D5\x10D0\x10D7\x10D0 \x10D9\x10E0\x10D7\x10DD\x10DB\x10D0\x10D0\x10E1\x10D0\x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4,\x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4,",
+L"\x03A4\x03B7 \x03B3\x03BB\x03CE\x03C3\x03C3\x03B1 \x03BC\x03BF\x03C5 \x03AD\x03B4\x03C9\x03C3\x03B1\x03BD \x03B5\x03BB\x03BB\x03B7\x03BD\x03B9\x03BA\x03AE",
+L"\0"
+};
+
+
+
+char* utf16_to_utf8(wchar_t *srcstring)
 {
-    if ((pszTextUTF16 == NULL) || (*pszTextUTF16 == L'\0')) {
+    if ((srcstring == NULL) || (*srcstring == L'\0')) {
         return 0;
     }
-
-    size_t cchUTF16;
-    cchUTF16 = wcslen(pszTextUTF16) + 1;
+    size_t cchUTF16 = wcslen(srcstring) + 1;
     int cbUTF8 = WideCharToMultiByte(CP_UTF8, 0,
-        pszTextUTF16,
+        srcstring,
         (int)cchUTF16,
         NULL,
         0/* request buffer size*/,
         NULL,
         NULL);
-    
+
     char *pszUTF8 = (char*)CoTaskMemAlloc(sizeof(char) * (cbUTF8 + 1));
     int nc = WideCharToMultiByte(CP_UTF8, // convert to UTF-8
         0,       //default flags 
-        pszTextUTF16, //source wide string
+        srcstring, //source wide string
         (int)cchUTF16,     // length of wide string
         pszUTF8,      // destination buffer 
         cbUTF8,       // destination buffer size
         NULL,
         NULL);
-    
+
     if (!nc)
     {
         throw;
@@ -41,7 +50,7 @@ char* UTF16ToUTF8(wchar_t * pszTextUTF16)
     return pszUTF8;
 }
 
-wchar_t* UTF8ToUTF16(const char *utf8)
+wchar_t* utf8_to_utf16(const char *utf8)
 {
     // Special case of empty input string
     //wszTextUTF16
@@ -59,8 +68,8 @@ wchar_t* UTF8ToUTF16(const char *utf8)
         NULL,               // unused - no conversion done in this step
         0                   // request size of destination buffer, in wchar_t's
     );
-    
-    wszTextUTF16 = (wchar_t*)(CoTaskMemAlloc((cbUTF16 + 1 )  * sizeof(wchar_t) ));
+
+    wszTextUTF16 = (wchar_t*)(CoTaskMemAlloc((cbUTF16 + 1) * sizeof(wchar_t)));
     // Do the actual conversion from UTF-8 to UTF-16
     int nc = ::MultiByteToWideChar(
         CP_UTF8,            // convert from UTF-8
@@ -78,40 +87,21 @@ wchar_t* UTF8ToUTF16(const char *utf8)
     wszTextUTF16[nc] = '\0';
     return wszTextUTF16;
 }
-#endif
 
+char *get_utf8_string(int index) {
+    char *pszTextutf8 = utf16_to_utf8(utf8strings[index]);
+    return pszTextutf8;
+}
 
-LPSTR build_return_string(const char* pReturn)
+void free_utf8_string(char *str)
 {
-    char *ret = 0;
-    if (pReturn == 0 || *pReturn == 0)
-        return ret;
-
-    size_t strLength = strlen(pReturn);
-    ret = (LPSTR)(CoTaskMemAlloc(sizeof(char)* (strLength + 1)));
-    memset(ret, '\0', strLength + 1);
-    strncpy_s(ret, strLength + 1, pReturn, strLength);
-    return ret;
+    CoTaskMemFree(str);
 }
 
-// this is the same set as in managed side , but here 
-// string need to be escaped  , still CL applied some local and 
-// end up with different byte sequence.
-
-const int NSTRINGS = 6;
-#ifdef _WIN32
-wchar_t  *utf8Strings[] = { L"Managed",
-L"S\x00EEne kl\x00E2wen durh die wolken sint geslagen" ,
-L"\x0915\x093E\x091A\x0902 \x0936\x0915\x094D\x0928\x094B\x092E\x094D\x092F\x0924\x094D\x0924\x0941\x092E\x094D \x0964 \x0928\x094B\x092A\x0939\x093F\x0928\x0938\x094D\x0924\x093F \x092E\x093E\x092E\x094D",
-L"\x6211\x80FD\x541E\x4E0B\x73BB\x7483\x800C\x4E0D\x4F24\x8EAB\x4F53",
-L"\x10E6\x10DB\x10D4\x10E0\x10D7\x10E1\x10D8 \x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4,\x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4, \x10DC\x10E3\x10D7\x10E3 \x10D9\x10D5\x10DA\x10D0 \x10D3\x10D0\x10DB\x10EE\x10E1\x10DC\x10D0\x10E1 \x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4,\x10E1\x10DD\x10E4\x10DA\x10D8\x10E1\x10D0 \x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4, \x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4,\x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4,\x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4,\x10E8\x10E0\x10DD\x10DB\x10D0\x10E1\x10D0, \x10EA\x10D4\x10EA\x10EE\x10DA\x10E1, \x10EC\x10E7\x10D0\x10DA\x10E1\x10D0 \x10D3\x10D0 \x10DB\x10D8\x10EC\x10D0\x10E1\x10D0, \x10F0\x10D0\x10D4\x10E0\x10D7\x10D0 \x10D7\x10D0\x10DC\x10D0 \x10DB\x10E0\x10DD\x10DB\x10D0\x10E1\x10D0; \x10DB\x10DD\x10DB\x10EA\x10DC\x10D4\x10E1 \x10E4\x10E0\x10D7\x10D4\x10DC\x10D8 \x10D3\x10D0 \x10D0\x10E6\x10D5\x10E4\x10E0\x10D8\x10DC\x10D3\x10D4, \x10DB\x10D8\x10D5\x10F0\x10EE\x10D5\x10D3\x10D4 \x10DB\x10D0\x10E1 \x10E9\x10D4\x10DB\x10E1\x10D0 \x10DC\x10D3\x10DD\x10DB\x10D0\x10E1\x10D0, \x10D3\x10E6\x10D8\x10E1\x10D8\x10D7 \x10D3\x10D0 \x10E6\x10D0\x10DB\x10D8\x10D7 \x10D5\x10F0\x10EE\x10D4\x10D3\x10D5\x10D8\x10D3\x10D4 \x10DB\x10D6\x10D8\x10E1\x10D0 \x10D4\x10DA\x10D5\x10D0\x10D7\x10D0 \x10D9\x10E0\x10D7\x10DD\x10DB\x10D0\x10D0\x10E1\x10D0\x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4,\x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4,",
-L"\x03A4\x03B7 \x03B3\x03BB\x03CE\x03C3\x03C3\x03B1 \x03BC\x03BF\x03C5 \x03AD\x03B4\x03C9\x03C3\x03B1\x03BD \x03B5\x03BB\x03BB\x03B7\x03BD\x03B9\x03BA\x03AE",
-L"\0"
-};
+#else //Not WIndows
 
-#else
 //test strings
-const char  *utf8Strings[] = { "Managed",
+const char  *utf8strings[] = { "Managed",
 "Sîne klâwen durh die wolken sint geslagen",
 "काचं शक्नोम्यत्तुम् । नोपहिनस्ति माम्",
 "我能吞下玻璃而不伤身体",
@@ -119,8 +109,31 @@ const char  *utf8Strings[] = { "Managed",
 "Τη γλώσσα μου έδωσαν ελληνική",
 "\0"
 };
+
+char *get_utf8_string(int index) {
+    return (char*)utf8strings[index];
+}
+
+void free_utf8_string(char *str)
+{
+    // do nothing , we never allocated the temp buffer on non-windows 
+}
+
 #endif
 
+LPSTR build_return_string(const char* pReturn)
+{
+    char *ret = 0;
+    if (pReturn == 0 || *pReturn == 0)
+        return ret;
+
+    size_t strLength = strlen(pReturn);
+    ret = (LPSTR)(CoTaskMemAlloc(sizeof(char)* (strLength + 1)));
+    memset(ret, '\0', strLength + 1);
+    strncpy_s(ret, strLength + 1, pReturn, strLength);
+    return ret;
+}
+
 // Modify the string builder in place, managed side validates.
 extern "C" DLL_EXPORT void __cdecl StringBuilderParameterInOut(/*[In,Out] StringBuilder*/ char *s, int index)
 {
@@ -128,11 +141,7 @@ extern "C" DLL_EXPORT void __cdecl StringBuilderParameterInOut(/*[In,Out] String
     if (s == 0 || *s == 0)
         return;
 
-#ifdef _WIN32
-    char *pszTextutf8 = UTF16ToUTF8(utf8Strings[index]);
-#else
-    char *pszTextutf8 = (char*)utf8Strings[index];
-#endif
+    char *pszTextutf8 = get_utf8_string(index);
 
     // do byte by byte validation of in string
     size_t szLen = strlen(s);
@@ -151,48 +160,31 @@ extern "C" DLL_EXPORT void __cdecl StringBuilderParameterInOut(/*[In,Out] String
         s[i] = pszTextutf8[i];
     }
     s[outLen] = '\0';
-#ifdef _WIN32
-    CoTaskMemFree(pszTextutf8);
-#endif
+    free_utf8_string(pszTextutf8);
 }
 
 //out string builder
 extern "C" DLL_EXPORT void __cdecl  StringBuilderParameterOut(/*[Out] StringBuilder*/ char *s, int index)
 {
-
-#ifdef _WIN32
-    char *pszTextutf8 = UTF16ToUTF8(utf8Strings[index]);
-#else 
-    char *pszTextutf8 = (char*)utf8Strings[index];
-#endif
+    char *pszTextutf8 = get_utf8_string(index);
     // modify the string inplace 
     size_t outLen = strlen(pszTextutf8);
     for (size_t i = 0; i < outLen; i++) {
         s[i] = pszTextutf8[i];
     }
     s[outLen] = '\0';
-#ifdef _WIN32
-    CoTaskMemFree(pszTextutf8);
-#endif
+    free_utf8_string(pszTextutf8);
 }
 
 // return utf8 stringbuilder
-extern "C" DLL_EXPORT char* __cdecl  StringBuilderParameterReturn(int index) {
-
-#ifdef _WIN32
-    char *pszTextutf8 = UTF16ToUTF8(utf8Strings[index]);
-#else
-    char *pszTextutf8 = (char*)utf8Strings[index];
-#endif
+extern "C" DLL_EXPORT char* __cdecl  StringBuilderParameterReturn(int index) 
+{
+    char *pszTextutf8 = get_utf8_string(index);
     size_t strLength = strlen(pszTextutf8);
     LPSTR ret = (LPSTR)(CoTaskMemAlloc(sizeof(char)* (strLength + 1)));
     memcpy(ret, pszTextutf8, strLength);
     ret[strLength] = '\0';
-
-#ifdef _WIN32
-    CoTaskMemFree(pszTextutf8);
-#endif
-
+    free_utf8_string(pszTextutf8);
     return  ret;
 }
 
@@ -227,11 +219,7 @@ extern "C" DLL_EXPORT void _cdecl TestStructWithUtf8Field(struct FieldWithUtf8 f
     if (pszManagedutf8 == 0 || *pszManagedutf8 == 0)
         return;
 
-#ifdef _WIN32
-    pszNative = UTF16ToUTF8(utf8Strings[stringIndex]);
-#else 
-    pszNative = (char*)utf8Strings[stringIndex];
-#endif
+    pszNative = get_utf8_string(stringIndex);
     outLen = strlen(pszNative);
     // do byte by byte comparision
     for (size_t i = 0; i < outLen; i++) 
@@ -242,36 +230,24 @@ extern "C" DLL_EXPORT void _cdecl TestStructWithUtf8Field(struct FieldWithUtf8 f
             throw;
         }
     }
-#ifdef _WIN32
-    CoTaskMemFree(pszNative);
-#endif
+    free_utf8_string(pszNative);
 }
 
 // test c# out keyword
 extern "C" DLL_EXPORT void __cdecl StringParameterRefOut(/*out*/ char **s, int index)
 {
-#ifdef _WIN32
-    char *pszTextutf8 = UTF16ToUTF8(utf8Strings[index]);
-#else
-    char *pszTextutf8 = (char*)utf8Strings[index];
-#endif      
+    char *pszTextutf8 = get_utf8_string(index);
     size_t strLength = strlen(pszTextutf8);
      *s = (LPSTR)(CoTaskMemAlloc(sizeof(char)* (strLength + 1)));
     memcpy(*s, pszTextutf8, strLength);
     (*s)[strLength] = '\0';
-#ifdef _WIN32
-    CoTaskMemFree(pszTextutf8);
-#endif
+    free_utf8_string(pszTextutf8);
 }
 
 //c# ref
 extern "C" DLL_EXPORT void __cdecl StringParameterRef(/*ref*/ char **s, int index)
 {
-#ifdef _WIN32
-    char *pszTextutf8 = UTF16ToUTF8(utf8Strings[index]);
-#else
-    char *pszTextutf8 = (char*)utf8Strings[index];
-#endif
+    char *pszTextutf8 = get_utf8_string(index);
     size_t strLength = strlen(pszTextutf8);
     // do byte by byte validation of in string
     size_t szLen = strlen(*s);
@@ -292,9 +268,7 @@ extern "C" DLL_EXPORT void __cdecl StringParameterRef(/*ref*/ char **s, int inde
     *s = (LPSTR)(CoTaskMemAlloc(sizeof(char)* (strLength + 1)));
     memcpy(*s, pszTextutf8, strLength);
     (*s)[strLength] = '\0';
-#ifdef _WIN32
-    CoTaskMemFree(pszTextutf8);
-#endif
+    free_utf8_string(pszTextutf8);
 }
 
 // delegate test
@@ -302,13 +276,9 @@ typedef void (__cdecl * Callback)(char *text, int index);
 extern "C" DLL_EXPORT void _cdecl Utf8DelegateAsParameter(Callback managedCallback)
 {
     for (int i = 0; i < NSTRINGS; ++i) 
-    {
-        char *pszNative = 0;
-#ifdef _WIN32
-        pszNative = UTF16ToUTF8(utf8Strings[i]);
-#else 
-        pszNative = (char*)utf8Strings[i];
-#endif
+    {        
+        char *pszNative = get_utf8_string(i);
         managedCallback(pszNative, i);
+        free_utf8_string(pszNative);
     }
 }
\ No newline at end of file