简体   繁体   中英

How to change the encoding of a Process's Standard Input in C#?

I am trying to write to the Standard Input of a Process (a C++ program) in C#. The problem is that the C++ program seems to not be able to read what I write from my C# app. Here are both of the programs:

// C#
static void Main(string[] args) {
    Console.InputEncoding = Encoding.Unicode;
    Console.OutputEncoding = Encoding.Unicode;

    Process CoutN = new Process();
    CoutN.StartInfo.FileName = @"C:\Users\Vesk\Desktop\CoutN.exe";
    CoutN.StartInfo.UseShellExecute = false;
    CoutN.StartInfo.RedirectStandardInput = true;
    CoutN.StartInfo.RedirectStandardOutput = false;

    CoutN.Start();
    CoutN.StandardInput.WriteLine("5");

    CoutN.WaitForExit();

    Console.ReadKey();
}
// C++
int main() {
    int n;
    std::cin >> n;
    std::cout << "N is " << n << std::endl;
    return 0;
}

Here is the output from my C# program: N is 0 . It should instead be N is 5 .

From what I could understand the encoding that C# uses for a Process's Input/Output Stream is the same as the one used by the Console. Here's the thing though, in my C# program I'll need to be able to use the Console to input cyrillic text (as well as other non-ASCII text). The only Console Encoding which seems to work for that is Encoding.Unicode (which apparently is just UTF-16 LE).

But it seems that when I try to write to the Process's Input Stream, it just can't understand that and it outputs N is 0 for some reason. From what I understand this is because UTF-16 is not compatible with ASCII (or whatever the C++ iostream expects).

So is there a way to actually change the Encoding that the Process's Standard Input uses?

Here is what I have tried/cannot try:

  • I don't want to change the Console's Encoding, because I plan on running the Process in an asynchronously running method and I want to still be able to interface with the C# program, so I fear that it will mess things up, even if I just change the Encoding, only while writing to the Process and then change it back again.
  • I know that the C++ program could probably be changed so that it can read UTF-16, but I don't want to do that since my C# program will have to be able to run and "interface" with all kinds of C++ programs, which use the simple iostream ( cin , cout ). ( Edit for clarification: My C# program will only ever need to "send" ASCII text to the C++ program)
  • I did try to Change the Console's Encoding to Encoding.ASCII and it worked. It also worked if I just left the Console at it's default Encoding. But again this will not work for me, because these encodings don't seem to work with Cyrillic.
  • I tried setting the Console's Input Encoding to Encoding.UTF8 and that didn't work, although I wouldn't have been able to use that anyway, because it doesn't seem to work with Cyrillic text in my C# app.
  • I tried to change CoutN.StandardInput.Encoding , but unfortunately it is a read-only property.
  • I tried to also redirect the Standard Output, just to see if it works, and weirdly enough it does. I can just use CoutN.StandardOutput.ReadToEnd() and it works and the output from the C++ program is read correctly (still says N is 0 though). But for some reason the Standard Input is different.
  • I tried to just not redirect the Standard Input, again just to see if it works, and again very weirdly it did.. I just wrote 5 in the C# program's Console and the output was N is 5 .
  • I tried to create a StreamWriter with a different encoding and write from there:
StreamWriter str = new StreamWriter(CoutN.StandardInput.BaseStream, Encoding.ASCII);
str.WriteLine("5");

But this didn't work either. I even tried basically all the Encodings and even no Encoding, but nothing worked.

  • I tried writing to the BaseStream myself:
byte[] buffer = Encoding.ASCII.GetBytes("5");
CoutN.StandardInput.BaseStream.Write(buffer, 0, buffer.Length);
CoutN.StandardInput.WriteLine();

And that didn't work.

At this point I feel like I've exhausted all the options that I could try. Any help is appreciated, thanks in advance!

You don't get to chose what encoding the other process is using from your own code - if you're sending input to the standard input stream of an application that is expecting a specific encoding, then short of it having some setting to change that there's nothing you can do about it.

If you're interacting with the STDIO streams of another application, you are expected to match whatever encoding it is expecting, rather than the other way around. The encoding of the console doesn't really matter except in cases where the application inherits its encoding from the environment.

Indeed, if you're trying to use an encoding that supports Cyrillic characters, then the receiving application must have been designed to accommodate this. If the application was written by someone whose native character set only uses Latin characters then they may well have never bothered to do this. It's part of the reason for the push to adopt UTF8 everywhere since then you don't really need to think about it too much.

Edit: If you're trying to match the expected input encoding, then you do it thusly:

Process.StandardInput.Write(Encoding.ASCII.GetBytes("My String Here\r\n"));

Replacing Encoding.ASCII with whatever character set applies to get the appropriate GetBytes() method.

Note that the ASCII character set specifically does not include Cyrillic characters, so it's impossible to use them in an application that expects ASCII. If it expects some other character set that does support them then you're fine. Cyrillic uses Codepage 855 or needs UTF8.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM