title: Which Encoding is used by CharSet.Ansi?
body: <p>Which <code>System.Text.Encoding</code> is used by <code>CharSet.Ansi</code>?</p>
  
  <p>I want to decode a string in a .NET Core app (that was marshalled before by C++ code) without defining a structure and using <code>Marshal.PtrToStructure</code>.</p>
  
  <pre><code>Encoding.GetEncoding(???).GetString(...)
  </code></pre>
  
  <p>In a .NET Framework application <code>System.Text.Encoding.Default</code> works:</p>
  
  <pre><code>[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
  public struct Structure
  {
      [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)]
      public string FieldA;
  }
  
  public class Net461App
  {
      static void Main(string[] args)
      {
          var @struct = new Structure { FieldA = "äöüß" };
          byte[] buffer = ToByteArray(@struct);
          var unmarshalled = ToStructure&lt;Structure&gt;(buffer).FieldA;                     // "äöüß"
  
          Console.WriteLine(Encoding.Default.GetString(buffer).Trim('\0'));             // "äöüß"
          Console.WriteLine(Encoding.Default.EncodingName);                             // Western European (Windows)                    
          Console.WriteLine(Encoding.Default.CodePage);                                 // 1252
  
          int ansiCodePage = Thread.CurrentThread.CurrentCulture.TextInfo.ANSICodePage; // 1252
          Encoding ansiEncoding = Encoding.GetEncoding(ansiCodePage);                   // works
          Console.WriteLine(ansiEncoding.GetString(buffer).Trim('\0'));                 // "äöüß"
          Console.WriteLine(ansiEncoding.EncodingName);                                 // Western European (Windows) 
          Console.WriteLine(ansiEncoding.CodePage);                                     // 1252 
      }
  
      public static byte[] ToByteArray&lt;T&gt;(T structure) where T : struct
      {
          var buffer = new byte[Marshal.SizeOf(structure)];
          IntPtr handle = Marshal.AllocHGlobal(buffer.Length);
          try
          {
              Marshal.StructureToPtr(structure, handle, true);
              Marshal.Copy(handle, buffer, 0, buffer.Length);
              return buffer;
          }
          finally
          {
              Marshal.FreeHGlobal(handle);
          }
  
      }
  
      public static T ToStructure&lt;T&gt;(byte[] buffer) where T : struct
      {
          IntPtr handle = Marshal.AllocHGlobal(buffer.Length);
          try
          {
              Marshal.Copy(buffer, 0, handle, buffer.Length);
              return Marshal.PtrToStructure&lt;T&gt;(handle);
          }
          finally
          {
              Marshal.FreeHGlobal(handle);
          }
  
      }
  }
  </code></pre>
  
  <p><code>Encoding.Default</code> is the same as <code>Thread.CurrentThread.CurrentCulture.TextInfo.ANSICodePage</code> which both produce the same string as <code>CharSet.Ansi</code>. But is <code>TextInfo.ANSICodePage</code> always the same as <code>CharSet.Ansi</code>? </p>
  
  <p><code>Encoding.Default</code> is different in .NET Core and the code page 1252 is not supported:</p>
  
  <pre><code>public class NetCore2App
  {
      static void Main(string[] args)
      {
          var @struct = new Structure { FieldA = "äöüß" };
          byte[] buffer = ToByteArray(@struct);
          var unmarshalled = ToStructure&lt;Structure&gt;(buffer).FieldA;                     // "äöüß"
  
          Console.WriteLine(Encoding.Default.GetString(buffer).Trim('\0'));             // "????"
          Console.WriteLine(Encoding.Default.EncodingName);                             // Unicode(UTF - 8)                
          Console.WriteLine(Encoding.Default.CodePage);                                 // 65001
  
          int ansiCodePage = Thread.CurrentThread.CurrentCulture.TextInfo.ANSICodePage; // 1252
          Encoding ansiEncoding = Encoding.GetEncoding(ansiCodePage);                   // throws "No data is available for encoding 1252."
          Console.WriteLine(ansiEncoding.GetString(buffer).Trim('\0'));                 // ...
          Console.WriteLine(ansiEncoding.EncodingName);                                 // ...
          Console.WriteLine(ansiEncoding.CodePage);                                     // ...
      }
      // ...
  }
  </code></pre>
  
  <p><strong>Update:</strong></p>
  
  <p>Investigating the suggestion to use <a href="https://www.nuget.org/packages/System.Text.Encoding.CodePages/" rel="nofollow noreferrer">System.Text.Encoding.CodePages</a> I found the following hint about getting the systems current ANSI code page:</p>
  
  <p><code>Encoding.GetEncoding</code></p>
  
  <ul>
  <li><a href="http://To%20get%20the%20encoding%20associated%20with%20the%20default%20ANSI%20code%20page%20in%20the%20operating%20system&#39;s%20regional%20and%20language%20settings,%20you%20can%20either%20supply%20a%20value%200%20for%20the%20codepage%20argument" rel="nofollow noreferrer">To get the encoding associated with the default ANSI code page in the operating system's regional and language settings, you can either supply a value 0 for the codepage argument</a></li>
  <li><a href="https://docs.microsoft.com/en-us/dotnet/api/system.text.encoding.registerprovider?view=netframework-4.7.1" rel="nofollow noreferrer">If the registered provider is the CodePagesEncodingProvider, the method returns the encoding that matches the system active code page when running on the Windows operating system.</a></li>
  </ul>
  
  <p>The following seems to work:</p>
  
  <pre><code>Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
  int currentAnsiCodePage = Encoding.GetEncoding(0).CodePage;
  Encoding encoding = Encoding.GetEncoding(currentAnsiCodePage);
  </code></pre>
  
  <p>Each of the following gives me the same code page that correctly decodes the string in my test</p>
  
  <ul>
  <li>Encoding.GetEncoding(0).CodePage (requires <code>CodePagesEncodingProvider</code> registration)</li>
  <li>Thread.CurrentThread.CurrentCulture.TextInfo.ANSICodePage</li>
  <li>CultureInfo.CurrentCulture.TextInfo.ANSICodePage</li>
  </ul>
  
  <p>Not sure which one is preferable and works an all machines.</p>