2015-12-22 10 views
5

Próbuję uzyskać wszystkie komunikaty Exception w języku angielskim, bez względu na to, w jakim języku jest komputer, na którym działa mój program.Jak uzyskać błąd Win32Exception w języku angielskim?

jakie udało się uzyskać niemal wszystkie komunikaty o wyjątkach w języku angielskim używając odpowiedzi z następujących stanowisk: Exception messages in English? i niektóre inne rozwiązanie znalazłem (jak przy użyciu odbicia zmienić domyślną CultureInfo). Mam specyficzny problem z SocketException, Bez względu na to, co robię, otrzymuję go w domyślnym języku maszyny.

stworzyłem program testowy, aby pokazać problem: Program ten test drukowania wyjątków w języku domyślnym:

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

Wynik ten na moim komputerze następujący tekst:

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

Na maszynie japońskiej zapisuje wszystkie wyjątki w języku japońskim (czego nie rozumiem):

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

(Japoński "\" wygląda inaczej w japońskiej maszynie, ale po skopiowaniu do mojego urządzenia jest oznaczony jako "\")

Po połączeniu odpowiedzi, które znalazłem, wprowadziłem następujące rozwiązanie: tak teraz wygląda to tak:

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

teraz na japońskiej maszynie to napisać wyjątki plików po angielsku, ale są wyjątki Net.socket nadal w języku japońskim:

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

ja również testowane jakiś inny wyjątki, niektóre wyjątki są teraz wyświetlane w języku angielskim, bu nie wszystkie z nich, wyjątki gniazd są trwałe. Jak widać, wyjątek pliku został przetłumaczony na angielski, ale wyjątek gniazda jest nadal w języku japońskim.

Testowałem to w prawie każdym środowisku .NET (od 2.1 do 4.5), wciąż takie same.

  • Czy istnieje pełne rozwiązanie dla wszystkich wyjątków?
  • Czy coś przeoczyłem?
  • Czy powinienem zrobić cokolwiek innego?
  • Może istnieje inny sposób uruchomienia programu na obcej maszynie i ustawienia zmiennej środowiskowej, aby uzyskać wyjście angielskie?

Odpowiedz

3

mam rozwiązanie więc będę go przesłać tutaj w przypadku gdy ktoś będzie go potrzebować. Jeśli ktokolwiek ma lepsze rozwiązanie, będę szczęśliwy, więc proszę o komentarz.

W przypadku Win32Exception, możemy użyć FormatMessage i przetłumaczyć kod błędu zarówno na angielski, jak i domyślny, i zastąpić domyślny angielski. Jeśli wezmę angielski bez wymiany, stracę parametry. więc w przypadku, gdyby zastąpienie nie powiodło się, zwrócę wyjątek z dodatkowym opisem w języku angielskim.

Oto moje pełne rozwiązanie:

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

Nie otrzymuję żadnego angielskiego tekstu, ani w VS2008 (.net 3.5), ani w VS2015 (.net 4.5.2). defSb zawiera niemiecki tekst, engSb nie zawiera nic. –

+0

defLangID jest identyfikatorem języka, użyłem eng-us w mojej próbce, ale wygląda na to, że twoja maszyna go nie obsługuje, ale może obsługuje inne eng. język? może eng-uk? Możesz spróbować użyć innych ustawień narodowych, zobacz pełną listę tutaj: https://msdn.microsoft.com/en-us/library/windows/desktop/dd318693(v=vs.85).aspxhttps://msdn.microsoft. com/en-us/library/windows/desktop/dd318693 (v = vs.85) .aspx – SHR

1

A SocketException to Win32Exception. Podobnie jak wszystkie inne klasy, które pochodzą z Win32Exception, pobiera swoją wiadomość z Windows przy użyciu Win32Exception.GetErrorMessage(int error), która używa FormatMessage w Kernel32.DLL.

W ten sposób wiadomość skutecznie pochodzi z systemu Windows, a nie z .NET. System Windows wyświetli komunikat w języku wyświetlania systemu Windows, a także AFAIK. Nic nie możesz zrobić w tym programie .NET.

+1

znalazłem (i przesłanych w Edit) to rozwiązanie dla problemu, Twój komentarz był bardzo pomocny. Dzięki jeszcze raz. Gdybym mógł, znowu będę głosować! (Właśnie zdałem sobie sprawę, że mogę głosować nad inną z twojej odpowiedzi ...) – SHR

1

Być może trzeba będzie zawinąć wiersz, który drukuje błąd do konsoli w osobnym wątku, który ma ustawiony język angielski, ponieważ kod wyjątków Framework ładuje komunikaty o błędach z jego zasobów w oparciu o bieżące ustawienia narodowe wątku. tutaj jest to, co mówię w kawałku kodu:

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

Czy próbowałeś tego? Wiadomość nie jest ładowana przez strukturę, ale przez system Windows. Nie pochodzi z zasobów platformy .NET. Wiadomość jest ustawiana w wyjątku w czasie budowy. Wątpię, czy przeczytanie właściwości wiadomości w wątku, który ustawił kulturę en-US, automatycznie przetłumaczy tekst japoński na angielski. –

+0

Zmieniłem 'CurrentCulture' w moim kodzie dla wszystkich wątków, to nie pomogło. dodatkowy wątek może pomóc, jeśli chcesz zachować oba języki. – SHR

Powiązane problemy