簡體   English   中英

如何獲得英文的Win32Exception?

[英]How to get Win32Exception in English?

無論我的程序運行在哪種計算機上,我都試圖以英語獲取所有的Exception消息。

我已經使用以下帖子中的答案設法獲得了幾乎所有的英文異常消息英文異常消息? 和其他一些我發現的解決方案(例如使用反射更改默認的CultureInfo )。 我有SocketException特定問題,無論我在做什么,我都使用默認計算機的語言來獲取它。

我創建了一個測試程序來顯示問題:此測試程序將以默認語言打印異常:

using System;
using System.Text;
using System.Threading;
using System.IO;
using System.Net.Sockets;
using System.Reflection;
using System.Globalization;

namespace TestApp
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                //I'm not listening on the following port:
                TcpClient s = new TcpClient("localhost", 2121);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Socket exception: " + ex.Message);
            }
            try
            {
                //the following file doesn't exists:
                File.ReadAllText("filenotexist.txt");
            }
            catch (Exception ex)
            {
                Console.WriteLine("File exception: " + ex.Message);
            }
        }
    }
}

此結果在我的機器上顯示以下文本:

H:\Shared>Test-def.exe
Socket exception: No connection could be made because the target machine actively refused it 127.0.0.1:2121
File exception: Could not find file 'H:\Shared\filenotexist.txt'.

在日語機器上,它用日語編寫所有異常(我不理解):

Z:\>Test-def.exe
Socket exception: 対象のコンピューターによって拒否されたため、接続できませんでした。 127.0.0.1:2121
File exception: ファイル 'Z:\filenotexist.txt' が見つかりませんでした。

(日語'\\'在日語機器中看起來有所不同,但是當復制到我的機器時,它顯示為'\\')

因此,通過結合找到的答案,我實現了以下解決方案,因此現在看起來像這樣:

namespace TestApp
{
    class Program
    {
        //will change CultureInfo to English, this should change all threads CultureInfo to English. 
        public static void SetEnglishCulture()
        {
            CultureInfo ci = new CultureInfo("en-US");
            //change CultureInfo for current thread:
            Thread.CurrentThread.CurrentUICulture = ci;
            Thread.CurrentThread.CurrentCulture = ci;

            //change CultureInfo for new threads:
            Type t = typeof(CultureInfo);
            try
            {
                t.InvokeMember("s_userDefaultCulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, ci, new object[] { ci });
                t.InvokeMember("s_userDefaultUICulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, ci, new object[] { ci });
            }
            catch { }
            try
            {
                t.InvokeMember("m_userDefaultCulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, ci, new object[] { ci });
                t.InvokeMember("m_userDefaultUICulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, ci, new object[] { ci });
            }
            catch { }
        }
        static void Main(string[] args)
        {
            //first thing: set CultureInfo to English:
            SetEnglishCulture();
            try
            {
                //I'm not listening on the following port:
                TcpClient s = new TcpClient("localhost", 2121);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Socket exception: " + ex.Message);
            }
            try
            {
                //the following file doesn't exists:
                File.ReadAllText("filenotexist.txt");
            }
            catch (Exception ex)
            {
                Console.WriteLine("File exception: " + ex.Message);
            }
        }
    }
}

現在,在日文計算機上,它用英語編寫文件異常,但Net.socket異常仍為日文:

Z:\>Test-en.exe
Socket exception: 対象のコンピューターによって拒否されたため、接続できませんでした。 127.0.0.1:2121
File exception: Could not find file 'Z:\filenotexist.txt'.

我還測試了其他一些異常,現在以英語顯示了一些異常,但並非所有異常,套接字異常都是持久的。 如您所見,文件異常已翻譯為英語,但是套接字異常仍為日語。

我已經在幾乎所有.NET框架(從2.1到4.5)中都進行了測試。

  • 是否有針對所有例外的完整解決方案?
  • 我錯過了什么嗎?
  • 我還應該做其他事情嗎?
  • 也許還有另一種方法可以在外部機器上運行程序,並設置一些環境變量以獲取英文輸出?

我有一個解決方案,因此如果有人需要它,我將在這里上傳。 如果有人有更好的解決方案,我將很高興知道,因此請發表評論。

Win32Exception情況下,我們可以使用FormatMessage並將錯誤代碼翻譯為英語和默認語言,並用英語替換默認語言。 如果我不取而代之以英語,則會丟失參數。 因此,如果替換失敗,我將以英語提供額外說明的異常。

這是我的完整解決方案:

using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Net.Sockets;
using System.Globalization;
using System.Reflection;
using System.ComponentModel;
using System.Runtime.InteropServices;

namespace TestCulture
{
    class Program
    {
        static void SetEnglishCulture()
        {
            CultureInfo ci = new CultureInfo("en-US");
            Thread.CurrentThread.CurrentCulture = ci;
            Thread.CurrentThread.CurrentUICulture = ci;
            Type type = typeof(CultureInfo);
            try
            {
                type.InvokeMember("s_userDefaultCulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, ci, new object[] { ci });
                type.InvokeMember("s_userDefaultUICulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, ci, new object[] { ci });
            } catch { }
            try
            {
                type.InvokeMember("m_userDefaultCulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, ci, new object[] { ci });
                type.InvokeMember("m_userDefaultUICulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, ci, new object[] { ci });
            } catch { }
        }
        [DllImport("kernel32.dll")]
        static extern uint FormatMessage(uint dwFlags, IntPtr lpSource, uint dwMessageId, uint dwLanguageId, StringBuilder lpBuffer, uint nSize, IntPtr Arguments);
        public static string Win32ExceptionInEnglish(Win32Exception ex)
        {
            const int nCapacity = 820; // max error length
            const uint FORMAT_MSG_FROM_SYS = 0x01000;
            const uint engLangID = (0x01<<10) | 0x09;
            const uint defLangID = 0x0;
            StringBuilder engSb = new StringBuilder(nCapacity);
            StringBuilder defSb = new StringBuilder(nCapacity);
            FormatMessage(FORMAT_MSG_FROM_SYS,IntPtr.Zero, (uint)ex.ErrorCode, defLangID, defSb, nCapacity, IntPtr.Zero);
            FormatMessage(FORMAT_MSG_FROM_SYS,IntPtr.Zero, (uint)ex.ErrorCode, engLangID, engSb, nCapacity, IntPtr.Zero);
            string sDefMsg = defSb.ToString().TrimEnd(' ','.','\r','\n');
            string sEngMsg = engSb.ToString().TrimEnd(' ','.','\r','\n');
            if(sDefMsg == sEngMsg) //message already in English (or no english on machine?)
            {
                //nothing left to do:
                return ex.Message;
            }
            else
            {
                string msg = ex.Message.Replace(sDefMsg,sEngMsg);
                if (msg == ex.Message)
                {
                    //replace didn't worked, can be message with arguments in the middle.
                    //I such as case print both: original and translated. to not lose the arguments.
                    return ex.Message + " (In English: " + sEngMsg + ")";
                }
                else 
                {
                    //successfuly replaced!
                    return msg;
                }
            }       
        }

        public static void Main(string[] args)
        {           
            SetEnglishCulture();
            try {
                // generate any exception ...
                const int notListenningPort = 2121;
                new TcpClient("localhost", notListenningPort);
            }
            catch(Win32Exception ex)//first try to cach win32 Exceptions
            {
                Console.WriteLine("W32 Exception: " + Win32ExceptionInEnglish(ex));
            }
            catch(Exception ex)//this fit to the rest .NET exceptions which affected by CultureInfo
            {
                Console.WriteLine("Exception: " +ex.Message);
            }   
        }
    }
}

SocketExceptionWin32Exception 像從Win32Exception派生的所有其他類一樣,它使用Win32Exception.GetErrorMessage(int error)從Windows獲取其消息,后者在Kernel32.DLL中使用FormatMessage

這樣,消息實際上來自Windows,而不是來自.NET。 Windows將以Windows顯示語言和AFAIK返回一條消息,您無法在.NET程序中對此進行任何處理。

您可能必須在將語言環境設置為英語的單獨線程中將打印錯誤的行包裝到控制台,因為Framework異常代碼會基於當前線程語言環境從其資源中加載錯誤消息。 這是我在一些代碼中談論的內容:

    static void Main(string[] args) {

    try {
        TcpClient c = new TcpClient("localhost", 1234);
    }
    catch (Exception ex) {
        // thread that logs exception message to console
        Thread logger = new Thread(new ParameterizedThreadStart(PrintException));
        logger.CurrentCulture = new System.Globalization.CultureInfo("en-US");
        logger.Start(ex);
    }


}

private static void PrintException(object ex) {
    Console.WriteLine("Error: " + ((Exception)ex).Message);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM