1

I try to execute this code:

private void Test(object sender, RoutedEventArgs e)
    {
        ProcessStartInfo start = new ProcessStartInfo("cmd",
    "/c \"wbadmin start recovert -version:02/26/2014-17:38 -itemtype:File - items:C:\test\"");

        int exitCode;
        using (Process proc = Process.Start(start))
        {
            proc.ErrorDataReceived += cmd_Error;
            proc.OutputDataReceived += cmd_DataReceived;
            proc.WaitForExit();

            exitCode = proc.ExitCode;
        }
    }

    private void cmd_DataReceived(object sender, DataReceivedEventArgs e)
    {
        if (e.Data == null) return;

        var source = Encoding.Unicode;
        var target = Encoding.UTF8;

        var sBytes = source.GetBytes(e.Data);
        var tBytes = Encoding.Convert(source, target, sBytes);

        var tString = Encoding.UTF8.GetString(tBytes);
        Console.WriteLine(tString);
    }

But I got this string: "wbadmin 1.0 - ®≠·‚‡„¨•≠‚ ™Æ¨†≠§≠Æ© ·‚‡Æ™® †‡Â®¢†Ê®®" How can I decode this string?

Kirill
  • 1,412
  • 4
  • 21
  • 45

2 Answers2

2

Parsing output from the cmd can be a little tricky, since your cmd has its own code page, that is usually equal to system's default locale (you can change it manually, using, for example, chcp command).

Read this for details.

When redirecting output, the way that worked for me (tested, also with wbadmin) is the following:

  1. Get the default locale of your system:

    [DllImport("kernel32.dll")]
    public static extern int GetSystemDefaultLCID();
    
    private static int GetCmdCodePage()
    {
        int lcid = GetSystemDefaultLCID();
        var ci = System.Globalization.CultureInfo.GetCultureInfo(lcid);
        return ci.TextInfo.OEMCodePage;
    }
    
  2. Get the corresponding encoding:

        Encoding enc = null;
        try
        {
            enc = Encoding.GetEncoding(GetCmdCodePage());
        }
        catch (Exception)
        {
            enc = Encoding.GetEncoding(855); // the value for Cyrillic
        }
    
  3. Set the encoding for the process:

        if (!File.Exists(Path.Combine(Environment.SystemDirectory, @"wbadmin.exe")))
        {
            Console.WriteLine("wbadmin.exe not found");
            return;
        }
        Process pr = new Process();
        ProcessStartInfo psi = new ProcessStartInfo(@"wbadmin.exe");
        psi.WindowStyle = ProcessWindowStyle.Hidden;
        psi.CreateNoWindow = true;
        psi.UseShellExecute = false;
        psi.Arguments = "/?"; // prints avaliable commands
        psi.RedirectStandardOutput = true;
        psi.RedirectStandardError = true;
        psi.Verb = "runas";
        psi.StandardOutputEncoding = enc;
        psi.StandardErrorEncoding = enc;
        pr.StartInfo = psi;
        pr.Start();
    
        pr.WaitForExit(1000);
        string error = pr.StandardError.ReadToEnd();
    
        if (!string.IsNullOrEmpty(error))
        {
            Console.WriteLine("error: " + error);
            pr.Close();
            pr.Dispose();
            return;
        }
    
        string output = pr.StandardOutput.ReadToEnd();
    
        pr.Close();
        pr.Dispose();
    
Community
  • 1
  • 1
Arie
  • 5,251
  • 2
  • 33
  • 54
0

Your code seemes to be entirely correct, but meaningless. The fact is that C# string is always UTF-16, no matter what. Your cmd_DataReceived method is converting UTF-16 to byte array, which contains UTF-8 representation of original string, and then converts it back to UTF-16 by calling Encoding.UTF8.GetString(tBytes).

It looks like external programm writes something to console in unknown encoding (UTF-8?), but cmd_DataReceived recieving it already decoded to UTF-16.

I assume, that if you're actualy want to convert your string from UTF-8 to UTF-16, your code shoud look like

private void cmd_DataReceived(object sender, DataReceivedEventArgs e)
    {
        if (e.Data == null) return;

        var source = Encoding.Unicode;
        var target = Encoding.UTF8;

        var sBytes = source.GetBytes(e.Data);

        var tString = Encoding.UTF8.GetString(sBytes);
        Console.WriteLine(tString);
    }