本文介绍了cmd.exe的Unicode问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我们有两个可执行文件:
1.)ascii.exe产生ascii输出,即

Lets asume we have two executables:
1.) ascii.exe produces ascii output, i.e.

   #include< stdio.h>
    int main(){
       printf("Hello World \ n");
      返回0;
    }

    #include<stdio.h>
    int main() {
        printf("Hello World\n");
        return 0;
    }

2.)utf16.exe产生utf16输出,即

2.) utf16.exe produces utf16 output, i.e.

   #include< fcntl.h>
    #include< io.h>
    #include< stdio.h>
    int main(){
       _setmode(_fileno(stdout),_O_U16TEXT);
       wprintf(L"Hello World \ n");
      返回0;
    }

    #include <fcntl.h>
    #include <io.h>
    #include <stdio.h>
    int main() {
        _setmode(_fileno(stdout), _O_U16TEXT);
        wprintf(L"Hello World\n");
        return 0;
    }

"cmd.exe";支持ascii和utf16输出模式:可以通过
选择    "cmd.exe" -> ASCII模式
    "cmd.exe/u"; -> unicode模式
两种模式之间的唯一区别是,在unicode模式下,所有输出均来自
"cmd.exe"本身(以及所有包含的工具,例如dir)将在utf16中,而在
中ascii模式下,所有"cmd.exe"输出将以ascii格式显示.

"cmd.exe" supports an ascii and an utf16 output mode: this can be selected by
    "cmd.exe"    -> ascii mode
    "cmd.exe /u" -> unicode mode
The only difference between the two modes is that in unicode mode all output from
the "cmd.exe" itself (and all included tools like dir) will be in utf16, while in
ascii mode all output of "cmd.exe" will be in ascii.

我的两个示例可执行文件的输出始终相同,这意味着
    "ascii.exe";总是产生ascii文字,
    "utf16.exe";总是产生utf16文字.

The output from my two example executables is always the same, means
    "ascii.exe" always produces ascii text and
    "utf16.exe" always produces utf16 text.

我意识到"cmd.exe"正确显示输出,这意味着它(或
别人)知道"数据采用哪种编码方式.

I realise that "cmd.exe" correctly displays the output, meaning that it (or
someone else) "knows" what kind of encoding the data has.

现在,我启动"cmd.exe";使用CreateProcess从另一个C程序读取并读取其输出
在带有ReadFile的管道上.
我的目标是使用unicode作为默认编码,但是如果我启动诸如
"ascii.exe";我将收到ascii数据. (请找到附件程序.)

Now I start "cmd.exe" from another C program with CreateProcess and read its output
over a pipe with ReadFile.
My target is to use unicode as default encoding, but if I start a program such as
"ascii.exe" I will receive ascii data. (Please find attached program.)

问题是:如何获取有关接收到的数据的编码的信息
(不用猜测)?
当"cmd.exe"出现时,是否有可能得到通知?正在切换其输出编码?

The problem is: How can I get information about the encoding of the received data
(without guessing)?
Is it possible to get informed, when "cmd.exe" is switching its output encoding?

 

   #include< windows.h>
    #include< stdio.h>
    #include< stdlib.h>
    #include< string.h>
    #include< fcntl.h>
    #include< io.h>
    #include< iostream>

    #include <windows.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <fcntl.h>
    #include <io.h>
    #include <iostream>

  处理avg_stdin_write;
   处理avg_stdout_read;
 
    int main(){
       SECURITY_ATTRIBUTES dsl_sec_attr;      //管道安全属性
       PROCESS_INFORMATION dsl_proc_info;      //子进程信息
       STARTUPINFO        dsl_start_info;    //子级开始信息
       BOOL                             bol_ret;                                  //返回几个func调用
      处理                                   avl_stdin_read;    //STDIN 阅读管道
      处理                                   avl_stdout_write;   //STDOUT写入管道

    HANDLE avg_stdin_write;
    HANDLE avg_stdout_read;
 
    int main() {
        SECURITY_ATTRIBUTES dsl_sec_attr;       // pipe security attributes
        PROCESS_INFORMATION dsl_proc_info;      // child process info
        STARTUPINFO         dsl_start_info;     // child start info
        BOOL                bol_ret;            // return for several func calls
        HANDLE              avl_stdin_read;     // STDIN  read  pipe
        HANDLE              avl_stdout_write;   // STDOUT write pipe

       //-------------------------------------------
       //为输入和输出创建管道:
       //-------------------------------------------
       //设置安全属性:
       dsl_sec_attr.nLength                           = sizeof(SECURITY_ATTRIBUTES);
       dsl_sec_attr.bInheritHandle      = TRUE;  //管道句柄是继承的
       dsl_sec_attr.lpSecurityDescriptor = NULL;

        //-------------------------------------------
        // create pipes for in- and output:
        //-------------------------------------------
        // set security attributes:
        dsl_sec_attr.nLength              = sizeof(SECURITY_ATTRIBUTES);
        dsl_sec_attr.bInheritHandle       = TRUE;  // pipe handles are inherited
        dsl_sec_attr.lpSecurityDescriptor = NULL;

       //创建子STDOUT管道:
       bol_ret = CreatePipe(& avg_stdout_read,& avl_stdout_write,& dsl_sec_attr,0);
       if(bol_ret == FALSE){
           printf("CreatePipe STDOUT管道失败\ n");
          返回EXIT_FAILURE;
       }

        // create child STDOUT pipe:
        bol_ret = CreatePipe( &avg_stdout_read, &avl_stdout_write, &dsl_sec_attr, 0 );
        if ( bol_ret == FALSE ) {
            printf( "CreatePipe STDOUT pipe failed\n" );
            return EXIT_FAILURE;
        }

       //确保未继承STDOUT的管道的读取句柄
       bol_ret = SetHandleInformation(avg_stdout_read,HANDLE_FLAG_INHERIT,0);
       if(bol_ret == FALSE){
           printf("SetHandleInformation STDOUT管道失败\ n");
          返回EXIT_FAILURE;
       }

        // ensure the read handle to the pipe for STDOUT is not inherited
        bol_ret = SetHandleInformation( avg_stdout_read, HANDLE_FLAG_INHERIT, 0 );
        if ( bol_ret == FALSE ) {
            printf( "SetHandleInformation STDOUT pipe failed\n" );
            return EXIT_FAILURE;
        }

       //创建子STDIN管道:
       bol_ret = CreatePipe(& avl_stdin_read,& avg_stdin_write,& dsl_sec_attr,0);
       if(bol_ret == FALSE){
           printf("CreatePipe STDIN管道失败\ n");
          返回EXIT_FAILURE;
       }

        // create child STDIN pipe:
        bol_ret = CreatePipe( &avl_stdin_read, &avg_stdin_write, &dsl_sec_attr, 0 );
        if ( bol_ret == FALSE ) {
            printf( "CreatePipe STDIN pipe failed\n" );
            return EXIT_FAILURE;
        }

       //确保不继承STDIN管道的读取句柄
       bol_ret = SetHandleInformation(avg_stdin_write,HANDLE_FLAG_INHERIT,0);
       if(bol_ret == FALSE){
           printf("SetHandleInformation STDIN管道失败\ n");
          返回EXIT_FAILURE;
       }

        // ensure the read handle to the pipe for STDIN is not inherited
        bol_ret = SetHandleInformation( avg_stdin_write, HANDLE_FLAG_INHERIT, 0 );
        if ( bol_ret == FALSE ) {
            printf( "SetHandleInformation STDIN pipe failed\n" );
            return EXIT_FAILURE;
        }

       //-------------------------------------------
       //创建子进程:
       //-------------------------------------------
       memset(& dsl_proc_info,0,sizeof(PROCESS_INFORMATION));

        //-------------------------------------------
        // create child process:
        //-------------------------------------------
        memset( &dsl_proc_info, 0, sizeof(PROCESS_INFORMATION) );

       //指定用于重定向的STDIN和STDOUT句柄.
       memset(& dsl_start_info,0,sizeof(STARTUPINFO));
       dsl_start_info.cb        = sizeof(STARTUPINFO);
       dsl_start_info.hStdError  = avl_stdout_write;
       dsl_start_info.hStdOutput = avl_stdout_write;
       dsl_start_info.hStdInput  = avl_stdin_read;
       dsl_start_info.dwFlags  | = STARTF_USESTDHANDLES;

        // specify the STDIN and STDOUT handles for redirection.
        memset( &dsl_start_info, 0, sizeof(STARTUPINFO) );
        dsl_start_info.cb         = sizeof(STARTUPINFO);
        dsl_start_info.hStdError  = avl_stdout_write;
        dsl_start_info.hStdOutput = avl_stdout_write;
        dsl_start_info.hStdInput  = avl_stdin_read;
        dsl_start_info.dwFlags   |= STARTF_USESTDHANDLES;

       bol_ret = CreateProcess(NULL,
              nbsp; bsp        " cmd/u",                                //子进程
              nbsp; bsp        NULL,            //处理安全性属性
              nbsp; bsp        NULL,            //主线程安全属性
              nbsp; bsp        TRUE,                                  //句柄是继承的
              nbsp; bsp        0,                         //创建标志
              nbsp; bsp        NULL,            //使用父母的环境
              nbsp; bsp        NULL,            //使用父级的当前目录
              nbsp; bsp        & dsl_start_info,   //STARTUPINFO指针
              nbsp; bsp        & dsl_proc_info  ); //接收PROCESS_INFORMATION
       if(bol_ret == FALSE){
           printf("CreateProcess失败\ n");
          返回EXIT_FAILURE;
       }

        bol_ret = CreateProcess( NULL,
                                 "cmd /u",          // child process
                                 NULL,              // process security attributes
                                 NULL,              // primary thread security attributes
                                 TRUE,              // handles are inherited
                                 0,                 // creation flags
                                 NULL,              // use parent's environment
                                 NULL,              // use parent's current directory
                                 &dsl_start_info,   // STARTUPINFO pointer
                                 &dsl_proc_info  ); // receives PROCESS_INFORMATION
        if ( bol_ret == FALSE ) {
            printf( "CreateProcess failed\n" );
            return EXIT_FAILURE;
        }

       //关闭未使用的管道:
       CloseHandle(avl_stdout_write);
       CloseHandle(avl_stdin_read  );

        // close unused pipes:
        CloseHandle( avl_stdout_write );
        CloseHandle( avl_stdin_read   );

       //-------------------------------------------
       //与子进程通信:
       //-------------------------------------------

        //-------------------------------------------
        // communicate with child process:
        //-------------------------------------------

       /*
           ...
           ...
           ...
       */

        /*
            ...
            ...
            ...
        */

      返回EXIT_SUCCESS;
    }

        return EXIT_SUCCESS;
    }

推荐答案

我有兴趣学习该问题的其他解决方案.

I am interested to learn any other solution of this question.


这篇关于cmd.exe的Unicode问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-28 08:25