【问题标题】:How can I ENABLE_VIRTUAL_TERMINAL_PROCESSING?如何启用_VIRTUAL_TERMINAL_PROCESSING?
【发布时间】:2019-03-07 13:23:24
【问题描述】:

前段时间我注意到有一个新的控制台模式ENABLE_VIRTUAL_TERMINAL_PROCESSING,我决定尝试一下。这是我的示例代码:

// File: test1.c
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

const char * const TEST_STRING = "\x1B[31;1mRed\x1B[0m \x1B[32;1mGreen\x1B[0m \x1B[34;1mBlue\x1B[0m";

void ErrorExit(const char* errorMessage) {
    puts(errorMessage);
    exit(1);
}

int main(int argc, char** argv) {
    if (argc != 2) {
        ErrorExit("Usage: program (enable|disable|test|sample)");
    }

    HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE), hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
    DWORD dwMode;

    char *cmd = argv[1];
    if (!strcmp(cmd, "enable")) {
        /*
        GetConsoleMode(hInput, &dwMode);
        dwMode |= ENABLE_VIRTUAL_TERMINAL_INPUT;
        SetConsoleMode(hInput, dwMode);
        */

        GetConsoleMode(hOutput, &dwMode);
        dwMode |= ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING;
        if (!SetConsoleMode(hOutput, dwMode)) {
            ErrorExit("SetConsoleMode failed.");
        }
    }
    else if (!strcmp(cmd, "disable")) {
        /*
        GetConsoleMode(hInput, &dwMode);
        dwMode &= ~ENABLE_VIRTUAL_TERMINAL_INPUT;
        SetConsoleMode(hInput, dwMode);
        */

        GetConsoleMode(hOutput, &dwMode);
        dwMode &= ~ENABLE_VIRTUAL_TERMINAL_PROCESSING;
        if (!SetConsoleMode(hOutput, dwMode)) {
            ErrorExit("SetConsoleMode failed.");
        }
    }
    else if (!strcmp(cmd, "test")) {
        puts(TEST_STRING);
    }
    else if (!strcmp(cmd, "sample")) {
        SetConsoleTextAttribute(hOutput, 0x0C);
        printf("Red");
        SetConsoleTextAttribute(hOutput, 0x07);
        printf(" ");
        SetConsoleTextAttribute(hOutput, 0x0A);
        printf("Green");
        SetConsoleTextAttribute(hOutput, 0x07);
        printf(" ");
        SetConsoleTextAttribute(hOutput, 0x09);
        printf("Blue");
        SetConsoleTextAttribute(hOutput, 0x07);
        printf("\n");
    }
    else {
        ErrorExit("Invalid command!");
    }
    return 0;
}

代码成功编译成test1.exe,但没有按预期工作:

我很确定我的其他一切都是正确的。我正在运行最新的 Windows 10 Enterprise 64 位,版本 10.0.17763.1

我也试过了,但没有任何区别:

else if (!strcmp(cmd, "test")) {
    DWORD dwNumber = strlen(TEST_STRING), dwWritten;
    WriteConsole(hOutput, TEST_STRING, dwNumber, &dwWritten, NULL);
    puts("");
}

那么为什么我的代码不工作(在运行test1 enable 之后,以test1 test 调用时仍然产生垃圾)?

【问题讨论】:

  • MS man page 说的是 ENABLE_VIRTUAL_TERMINAL_PROCESSING当使用 WriteFileWriteConsole 编写时,字符被解析为 VT100 和类似的控制字符序列,控制光标移动、颜色/字体模式以及其他也可以通过现有控制台 API 执行的操作(我的粗体字)。这会有所作为吗?
  • @WeatherVane 我试过WriteConsole(替换为puts)但没有任何区别。
  • 当然putsprintf是C库函数,最终都要调用WinAPIWriteFileWriteConsole,最终进行NT系统调用如NtWriteFile和@987654340 @.

标签: c windows console windows-console


【解决方案1】:

问题是,您对SetConsoleMode() 所做的设置仅影响正在运行的进程(以及潜在的子进程)。这意味着,它并不是真正的命令行窗口设置,也不是“传回”给父 shell 进程。您必须在输出之前直接设置它,即:

else if (!strcmp(cmd, "test")) {
    GetConsoleMode(hOutput, &dwMode);
    dwMode |= ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING;
    if (!SetConsoleMode(hOutput, dwMode)) {
        ErrorExit("SetConsoleMode failed.");
    }
    puts(TEST_STRING);
}

这应该可以如您所愿。

【讨论】:

  • 注意注释代码,似乎保留了输入模式。在test1 enable 之后我无法使用箭头键,这就是我注释掉输入模式部分的原因。
  • @iBug 所以你是说它也不像我建议的那样工作?
  • 它似乎正在工作。你能解释一下输入部分(我上面的评论)吗?
  • @iBug 嗯,好问题。那么,在您观察到“启用”之后,按下向上箭头会在父 shell 中显示类似 [A 的内容?在“禁用”之后就消失了?
  • 没错。取消注释输入部分后,向上箭头键生成^[[A,禁用后显示之前的CMD命令。
猜你喜欢
  • 2018-03-13
  • 1970-01-01
  • 2016-04-09
  • 2013-03-21
  • 2011-06-10
  • 2015-06-14
  • 2014-01-19
  • 2015-09-17
  • 2021-12-07
相关资源
最近更新 更多