Batch file ANSI颜色集图形格式副本在批处理中期中断并在继续后工作

Batch file ANSI颜色集图形格式副本在批处理中期中断并在继续后工作,batch-file,cmd,windows-10,ansi,windows-console,Batch File,Cmd,Windows 10,Ansi,Windows Console,我有一个批处理,它有一个子部分,迭代文件中的行,让exe尝试运行,然后批处理根据exe的退出代码对exe进行排序 出于某种原因,ANSI SGR似乎在设置上一个图形格式副本后中断或回显文字文本,而不是重新呈现它 我回去重新引用了这篇文章和原始文档,但我不确定为什么在第一行被回音后,我的批处理的这个特定区域会破坏控制台内的ANSI颜色 我用记事本替换了我的工具,你可以手动关闭记事本以获得零退出,或者使用控制面板结束进程以获得非零退出 test\u map.log的内容应该不会太重要,因为您实际上只

我有一个批处理,它有一个子部分,迭代文件中的行,让exe尝试运行,然后批处理根据exe的退出代码对exe进行排序

出于某种原因,ANSI SGR似乎在设置上一个图形格式副本后中断或回显文字文本,而不是重新呈现它

我回去重新引用了这篇文章和原始文档,但我不确定为什么在第一行被回音后,我的批处理的这个特定区域会破坏控制台内的ANSI颜色

我用记事本替换了我的工具,你可以手动关闭记事本以获得零退出,或者使用控制面板结束进程以获得非零退出

test\u map.log
的内容应该不会太重要,因为您实际上只是在使用记事本并向它发送一些参数。这就是我的目标:

C:\temp\qt_selftest.exe
C:\temp\sub_test.exe
C:\temp\cmd_module_test.exe
C:\temp\failing_qt_test.exe
C:\temp\passing_qt_test.exe
C:\temp\random_qt_test.exe
C:\temp\fail_module.exe
C:\temp\pass_module.exe
正如你从截图上看到的,这些线条被逐字处理。在我从中提取的实际批次中,它确实重新开始工作。。。但在那个街区内,只有在那个街区,它被打破了

你知道我会把事情搞砸吗

由于正在转换ESC序列,我无法直接共享代码,因此以下是要点:


如果需要在
[
,使用alt代码027,正如alt 0 2 7所说,这可以通过确保启用虚拟终端模式来解决。如果您只关心PowerShell的颜色,您可以将
/A
开关添加到对CMD.exe的调用中,否则您将需要一个像垫片一样处理此类问题的小进程,但也需要一个确保启用了VTM。这并不完全是一件坏事,因为这个抽象层在将来的用例和bug中可能会派上用场

这段代码中唯一“奇怪”的部分是我的rel path用法。这段代码是一个子目录中的进程填充程序,用于从上一个目录运行批处理填充程序

代码的重要部分是在获得控制台句柄后要包含和启用VTM for StdOut的头

#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <Windows.h>

#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
#endif

bool uses_whitespace(std::string test_string)
{
    size_t path_white_space_query = test_string.find(' ', 0);

    if (path_white_space_query != std::string::npos)
    {
        return true;
    }

    return false;
}

int main(int argc, char* argv[])
{
    std::string this_app_path = std::string(argv[0]);

    auto it = this_app_path.find_last_of("\\", std::string::npos);

    std::string path(this_app_path, 0, it);

    // Just forwarding the args that were sent to this shim to a batch in a known location,
    // making sure whitespace arguments keep their quotes when forwarded.

    // CMD.exe will need proper quote-handling, or the call will get mangled.
    std::string str = "C:\\Windows\\System32\\cmd.exe /C \"\"" + path + "\\..\\app_shim.bat\"";
    std::vector<std::string> args;
    std::copy(argv + 1, argv + argc, std::back_inserter(args));

    for (auto const& arg : args)
    {
        if (uses_whitespace(arg))
        {
            str += (" \"" + arg + "\"");
        }
        else
        {
            str += (" " + arg);
        }
    }

    // end-of-CMD-call final wrapping quote
    str += "\"";

    HANDLE stdOutHandle = GetStdHandle(STD_OUTPUT_HANDLE);

    DWORD mode = 0;
    GetConsoleMode(stdOutHandle, &mode);
    SetConsoleMode(stdOutHandle, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);

    int exit_code = system(str.c_str());

    CloseHandle(stdOutHandle);

    return exit_code;
}
#包括
#包括
#包括
#包括
#包括
#ifndef启用虚拟终端处理
#定义启用虚拟终端处理0x0004
#恩迪夫
bool使用_空格(std::string test_string)
{
size\u t path\u white\u space\u query=test\u string.find(“”,0);
if(路径\白空间\查询!=std::string::npos)
{
返回true;
}
返回false;
}
int main(int argc,char*argv[])
{
std::string this_app_path=std::string(argv[0]);
auto it=此应用程序路径。查找(“\\”,std::string::npos)中的最后一个路径;
std::字符串路径(此路径,0,it);
//只是将发送到此垫片的参数转发到已知位置的批次,
//确保空格参数在转发时保留其引用。
//CMD.exe将需要正确的报价处理,否则调用将被破坏。
std::string str=“C:\\Windows\\System32\\cmd.exe/C\”“+path+”\\..\\app\\\u shim.bat\”;
std::向量args;
std::copy(argv+1,argv+argc,std::back_inserter(args));
用于(自动常量和参数:参数)
{
if(使用_空格(arg))
{
str+=(“\”+arg+“\”);
}
其他的
{
str+=(“”+arg);
}
}
//CMD调用结束最终包装报价
str+=“\”;
句柄stdOutHandle=GetStdHandle(标准输出句柄);
DWORD模式=0;
GetConsoleMode(stdOutHandle和模式);
设置控制台模式(stdOutHandle,模式|启用虚拟终端|处理);
int exit_code=system(str.c_str());
关闭手柄(stdOutHandle);
返回退出代码;
}

cmd在运行外部程序时禁用控制台的虚拟终端模式,在作为前台进程重新获得控制时恢复VT模式(如果这对您有帮助的话)。如果没有示例代码来重现问题,很难说得更多。在提交问题xD之前,您认为自己已经掌握了一切,这是一个尴尬的时刻谢谢,@eryksun!关于你的评论,有趣的是我用记事本替换掉的检查工具使用了
bool process\u created=CreateProcess(obj.process\u name.c\u str(),参数,NULL,NULL,FALSE,distached\u process,NULL,NULL,p\u startup\u info,p\u proc\u info);
,我最近没有对该工具做过很多更新,但我可能触发了一些改变其在批处理文件中行为的事件。也许我现在总是在cmd参数中填充至少要创建的进程,这一事实使它被认为是“外部的”。这是cmd.exe中的一个错误。启动时,它会保存原始控制台输出模式,该模式禁用了虚拟终端模式。当运行外部程序时,它会恢复此模式。程序退出后,它会重置自己启用了虚拟终端模式的模式。该错误出现在
for
循环语句中,一旦它恢复了startup console mode要执行notepad.exe,在循环退出之前,它不会重置为自己的模式设置。显然,这完全取决于在语句之间重置控制台模式的顶级批处理脚本评估循环。作为一种解决方法,您可以从启用VT模式的简单控制台程序运行cmd.exe。然后,当cmd恢复原始模式要运行外部程序,VT模式仍将启用。这应调用
GetConsoleMode
和/或VT标志进入当前模式,通过
SetConsoleMode
进行设置。此外,对于
StandardOutput
StandardError
,您不需要这样做;这将是一种罕见的情况,在这种情况下e句柄用于单独的控制台屏幕缓冲区。嗯,关于
STDERR
,这是一个很好的观点;感谢您提到这一点。我的批处理回音都不会转到
STDERR
,因此这实际上与我的用例无关,因为我所知道的所有应用程序或脚本都没有使用ANSI colo