我有一个为Windows编写的C / C ++程序,并使用Visual Studio编译。它是一个命令行工具,这意味着它可以合理地在Cygwin Bash下运行,可能在MinTTY中,并且它的一些用户现在正在这样做。
我想改变我的程序,让它与Cygwin更好玩。
我的程序目前使用Windows Console APIs输出漂亮的彩色文本并管理光标,并且通常是"交互式" (或"互动"对于20世纪80年代的定义"互动"),至少在其输出没有通过管道传输到文件时。
为了让我的程序能够更好地使用Cygwin,我可以让它发出ANSI \x1B[...
转义码而不是调用Console API,但真正的问题是知道何时这样做
我认为有四种情况:
作为交互式Windows控制台程序调用。 - > (使用控制台API。)
作为普通的Windows控制台程序调用,但用户正在将其输出汇总到某处。 - > (根本不发布任何样式或互动电话。)
由Bash或在MinTTY下作为交互式程序调用。 - > (使用ANSI转义码。)
由Bash调用,但是用户正在将输出汇总到某处。 - > (根本不发布任何样式或互动电话。)
我可以通过测试GetConsoleMode()
stdout
句柄成功或失败来区分案例1;如果成功,我肯定有一个Windows控制台,当我打开代码使用控制台API时就是这种情况。
我希望以不同的方式处理案例3并使用ANSI代码,但遗憾的是,案例2,3和4似乎几乎无法区分:
stdout
句柄似乎只是FILE_TYPE_PIPE
的不透明对象。OSTYPE
环境变量,至少猜测我在Cygwin下面,这将案例2与案例3和4区分开来。cygwin1.dll
,我可能会以某种方式使用其isatty()
,但我无法与之相关联,因为我的许多用户都没有(并赢得了&# #39; t)安装了Cygwin。 (即使有可能,我也会not at all convinced that'd work。)_isatty()
认为Cygwin Bash是一个管道,而不是一个交互式shell,因为它只是在引擎盖下使用GetFileType()
。简而言之,我没有明显的方法将案例3与案例4分开。
现在,我将案例3与案例2和案例4完全相同,而且Cygwin用户(包括我自己)获得了蹩脚的玻璃电传交互,而不是友好的交互式全屏显示,我真的很想解决这个问题。
那么有什么方法可以区分交互式 Cygwin调用与其他调用,所以我的本机Windows程序在Cygwin Bash或其他类似shell调用时表现得很好吗?
(重要提示: 是一个解决方案的解决方案:程序 不会 被编译为本机Cygwin程序。这是一个Windows程序,它是用Microsoft工具链编译的,它不会用GCC编译。目的是更改/更新它以表现得很好尽可能在Cygwin下 - 没有实际链接任何Cygwin DLL。我只能合理地为Windows分发一个可执行文件,而不是两个。)
答案 0 :(得分:0)
如果我可以链接cygwin1.dll,我可能会以某种方式使用它的isatty(),但我无法链接,因为我的许多用户没有(也不会)安装Cygwin。 (而且即使有可能,我也完全不相信它会工作。)
好的,您无法静态链接该DLL,但这并不意味着您无法尝试动态加载它。
您可以尝试LoadLibrary("cygwin1.dll")
。如果失败,那么它不会在cygwin下运行,你可以使用本机Windows函数来检测控制台类型。
另一方面,如果您可以打开该库(这意味着Cygwin在当前系统中可用),那么您可以执行对isatty()
的动态调用并使用结果查看是否输出被重定向。
编辑:加载cygwin DLL并调用函数并不容易,你需要先初始化lib,如link
所示摘录:
static BOOL setup_root()
{
HMODULE hCygwin = NULL;
// Load the cygwin dll into our application.
if(!load_cygwin_library(&hCygwin))
return FALSE;
// Init the cygwin environment. (Required)
if(!init_cygwin_library(hCygwin))
return FALSE;
有两个有趣的init例程。如果未调用init_cygwin_library
,则可能无法进一步调用:
static BOOL load_cygwin_library(HMODULE* hCygwin)
{
if((*hCygwin = GetModuleHandleW(cyglibrary)) == NULL)
if((*hCygwin = LoadLibraryW(cyglibrary)) == NULL)
return FALSE;
return TRUE;
}
static BOOL init_cygwin_library(HMODULE hCygwin)
{
cygwin_dll_init_fn cygwin_dll_init = NULL;
if((cygwin_dll_init = (cygwin_dll_init_fn)GetProcAddress(hCygwin,"cygwin_dll_init")) == NULL) {
FreeLibrary(hCygwin);
return FALSE;
}
cygwin_dll_init();
return TRUE;
}