如何获得英文的Win32Exception? [英] How to get Win32Exception in English?

查看:77
本文介绍了如何获得英文的Win32Exception?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

无论程序运行的机器是哪种语言,我都试图用英语获取所有 Exception 消息。

I'm trying to get all Exception messages in English, no matter what language is the machine my program running on.

我已经使用以下帖子中的答案设法获得了几乎所有的英语异常消息:
英语异常消息?
和我发现的其他一些解决方案(例如使用反射更改默认的 CultureInfo )。
我有 SocketException 的特定问题,无论我在做什么,我都使用默认计算机的语言来获取它。

I've manage to get almost all exception messages in English using answers from the following posts: Exception messages in English? and some other solution I've found (like using reflection to change the default CultureInfo). I have specific problem with SocketException, No matter what I'm doing I'm getting it in the default machine's language.

我创建了一个测试程序来显示问题:
此测试程序将以默认语言打印异常:

I've created a test program to show the problem: This test program will print Exceptions in default language:

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);
            }
        }
    }
}

此结果在我的计算机上显示以下文本:

This result on my machine the following text:

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'.

在日语机器上,它用日语写所有异常(我不理解):

On Japanese machine it write all exceptions in Japanese (which I don't understand):

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

(日语的 \在日语机器中看起来有所不同,但是当复制到我的机器上时显示为 \)

(The Japanese '\' looks different in Japanese machine, but when copied to my machine it shown as '\')

因此,通过结合我发现的答案,我实现了以下解决方案,因此现在看起来像这样:

So from combining of the answers I've found, I've implemented the following solution, so now it looks like this:

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异常仍是日文:

Now on Japanese machine it write the file exceptions in English but the Net.socket exceptions are still in Japanese:

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

我还测试了其他一些例外,某些例外现在以英语显示,但不是全部它们,套接字异常是持久的。如您所见,文件异常已翻译为英语,但是套接字异常仍为日语。

I've also tested some other exceptions, some exceptions are now shown in English, but not all of them, the socket exceptions are persistent. As you can see, the file exception had been translated to English, but the socket exception is still in Japanese.

我已经在几乎所有.NET框架中对其进行了测试(从2.1到4.5)仍然相同。

I've tested it in almost any .NET framework (from 2.1 to 4.5) still the same.


  • 是否有针对所有例外的完整解决方案?

  • 我错过了什么吗?

  • 我还应该做其他事情吗?

  • 也许还有另一种方法可以在外国计算机上运行程序,并设置一些环境变量以获取英语输出?

  • Is there a complete solution for all the exceptions?
  • Did I missed anything?
  • Should I do anything else?
  • Maybe there's other way to run program on foreign machine, and set some environment variable, to get English output?

推荐答案

我有一个解决方案,因此我将其上传到此处,以防有人需要。
如果有人有更好的解决方案,我很乐意知道,所以请发表评论。

I have a solution so I'll upload it here in case someone will need it. If anyone have a better solution I'll be happy to know so please comment.

如果出现 Win32Exception ,我们可以使用 FormatMessage 并将错误代码翻译为英语和默认语言,并用英语替换默认语言。
如果我选择不带替换的英语,则会丢失参数。因此,如果替换失败,我将以英语提供额外说明,并返回异常。

In case of Win32Exception, we can use FormatMessage and translate the error code to both English and default languages, and replace the default by English. If I take the English without replace, I lose the parameters. so in case the replace failed I'll return the Exception With additional description in English.

这是我的完整解决方案:

Here's my full solution:

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);
            }   
        }
    }
}

这篇关于如何获得英文的Win32Exception?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆