From a07c62d26371dc4e88acac62e35da6a93a7ba0c9 Mon Sep 17 00:00:00 2001 From: Bill Holmes Date: Mon, 20 May 2024 14:50:57 -0400 Subject: [PATCH] Fix System.Net.CookieContainer ANSI code page bug on Windows The call to GetNetworkParams returns a FIXED_INFO_W2KSP1 structure. The string fields of this struct are 8-bit ANSI strings an need to be marshaled MultiByteToWideChar. The existing behavior was using UTF-8 to decode the string which does not work correctly on Japanese systems --- .../Win32NetworkInterfaceMarshal.cs | 57 ++++++++++++++++--- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/mcs/class/System/System.Net.NetworkInformation/Win32NetworkInterfaceMarshal.cs b/mcs/class/System/System.Net.NetworkInformation/Win32NetworkInterfaceMarshal.cs index 71656efce7b1..56a131307474 100644 --- a/mcs/class/System/System.Net.NetworkInformation/Win32NetworkInterfaceMarshal.cs +++ b/mcs/class/System/System.Net.NetworkInformation/Win32NetworkInterfaceMarshal.cs @@ -34,6 +34,9 @@ class Win32NetworkInterface { [DllImport ("iphlpapi.dll", SetLastError = true)] static extern int GetNetworkParams (IntPtr ptr, ref int size); + [DllImport("kernel32.dll", SetLastError = true)] + static extern unsafe int MultiByteToWideChar(uint CodePage, uint dwFlags, byte* lpMultiByteStr, int cbMultiByte, char* lpWideCharStr, int cchWideChar); + static Win32_FIXED_INFO fixedInfo; static bool initialized = false; @@ -45,7 +48,36 @@ class Win32NetworkInterface { GetNetworkParams (ptr, ref len); ptr = Marshal.AllocHGlobal(len); GetNetworkParams (ptr, ref len); - fixedInfo = Marshal.PtrToStructure (ptr); + var fixedInfoUnmarshal = Marshal.PtrToStructure (ptr); + + unsafe string GetStringFromMultiByte(byte * bytes) + { + // passing CP_ACP or 0 as the CodePage argument to MultiByteToWideChar + // CP_ACP is the system default Windows ANSI code page identifier + var len1 = MultiByteToWideChar(0, 0, bytes, -1 , null, 0); + if (len1 == 0) + return string.Empty; + + var chars = new char[len1]; + fixed (char* pChars = chars) { + MultiByteToWideChar(0, 0, bytes, -1, pChars, len1); + } + return new string(chars); + } + + unsafe { + fixedInfo = new Win32_FIXED_INFO { + HostName = GetStringFromMultiByte(fixedInfoUnmarshal.HostName), + DomainName = GetStringFromMultiByte(fixedInfoUnmarshal.DomainName), + CurrentDnsServer = fixedInfoUnmarshal.CurrentDnsServer, + DnsServerList = fixedInfoUnmarshal.DnsServerList, + NodeType = fixedInfoUnmarshal.NodeType, + ScopeId = GetStringFromMultiByte(fixedInfoUnmarshal.ScopeId), + EnableRouting = fixedInfoUnmarshal.EnableRouting, + EnableProxy = fixedInfoUnmarshal.EnableProxy, + EnableDns = fixedInfoUnmarshal.EnableDns + }; + } initialized = true; } return fixedInfo; @@ -56,22 +88,31 @@ class Win32NetworkInterface { // They are mostly defined in iptypes.h (included by iphlpapi.h). // grep around /usr/include/w32api/* for identifiers you are curious. - [StructLayout (LayoutKind.Sequential)] struct Win32_FIXED_INFO { + public string HostName; + public string DomainName; + public IntPtr CurrentDnsServer; // to Win32IP_ADDR_STRING + public Win32_IP_ADDR_STRING DnsServerList; + public NetBiosNodeType NodeType; + public string ScopeId; + public uint EnableRouting; + public uint EnableProxy; + public uint EnableDns; + } + [StructLayout (LayoutKind.Sequential)] + unsafe struct Win32_FIXED_INFO_Marshal + { const int MAX_HOSTNAME_LEN = 128; const int MAX_DOMAIN_NAME_LEN = 128; const int MAX_SCOPE_ID_LEN = 256; - [MarshalAs (UnmanagedType.ByValTStr, SizeConst = MAX_HOSTNAME_LEN + 4)] - public string HostName; - [MarshalAs (UnmanagedType.ByValTStr, SizeConst = MAX_DOMAIN_NAME_LEN + 4)] - public string DomainName; + public fixed byte HostName[MAX_HOSTNAME_LEN+4]; + public fixed byte DomainName[MAX_DOMAIN_NAME_LEN+4]; public IntPtr CurrentDnsServer; // to Win32IP_ADDR_STRING public Win32_IP_ADDR_STRING DnsServerList; public NetBiosNodeType NodeType; - [MarshalAs (UnmanagedType.ByValTStr, SizeConst = MAX_SCOPE_ID_LEN + 4)] - public string ScopeId; + public fixed byte ScopeId[MAX_SCOPE_ID_LEN + 4]; public uint EnableRouting; public uint EnableProxy; public uint EnableDns;