c - 我如何与 Cygwin 相处融洽?

标签 c windows bash cygwin mintty

我有一个为 Windows 编写并使用 Visual Studio 编译的 C/C++ 程序。而且它是一个命令行工具,这意味着它可以合理地在 Cygwin Bash 下运行,可能在 MinTTY 中运行,并且它的一些用户现在正在这样做。

我想更改我的程序,使其更好地与 Cygwin 配合使用。

我的程序目前使用 Windows Console APIs输出漂亮的彩色文本并管理光标,并且通常是“交互的”(或 1980 年代定义的“交互”的“交互”),至少在其输出未通过管道传输到文件时是这样。

为了让我的程序更好地与 Cygwin 一起运行,我可以让它发出 ANSI \x1B[...转义代码而不是调用控制台 API,但真正的问题是知道何时这样做


我认为有四种情况:

  1. 作为交互式 Windows 控制台程序调用。 -->(使用控制台 API。)

  2. 作为普通 Windows 控制台程序调用,但用户在某处通过管道传输其输出。 -->(根本不发出任何样式或交互式调用。)

  3. 由 Bash 或 MinTTY 作为交互式程序调用。 -->(使用 ANSI 转义码。)

  4. 由 Bash 调用,但用户正在某处管道输出。 -->(根本不发出任何样式或交互式调用。)

我可以通过测试是否 GetConsoleMode() 来区分情况 1 stdout 成功或失败处理;如果成功,我肯定有一个 Windows 控制台,当我打开代码以使用控制台 API 时就是这种情况。

我想以不同的方式对待案例 3 并为其使用 ANSI 代码,但不幸的是,案例 2、3 和 4 似乎几乎无法区分:

  • stdout handle 似乎只是一个不透明的对象 FILE_TYPE_PIPE 对于所有三种情况。
  • 我可以使用 OSTYPE 环境变量,至少我猜我在 Cygwin 下,这将案例 2 与案例 3 和案例 4 区分开来。
  • 如果我能链接到 cygwin1.dll , 我也许可以用它的 isatty() ,但我无法对此进行链接,因为我的许多用户没有(也不会)安装 Cygwin。 (我是 not at all convinced that'd work,即使这是可能的。)
  • MSVC 的 native _isatty() 认为 Cygwin Bash 是一个管道,而不是一个交互式 shell,因为它只使用 GetFileType() 深入引擎盖。

简而言之,我看不到区分案例 3 和案例 4 的明显方法。

现在,我对待案例 3 的方式与案例 2 和案例 4 完全相同,而 Cygwin 用户(包括我自己)得到的是蹩脚的玻璃电传打字机交互,而不是友好的交互式全屏显示,我真的很想解决这个问题。


那么有什么方法可以区分交互式 Cygwin 调用和其他调用,这样我的 native Windows 程序在被 Cygwin Bash 或其他类似 shell 调用时可以正常运行吗?

(重要说明:一种不在考虑范围内的解决方案:程序不会被编译作为 native Cygwin 程序。这是一个 Windows 程序,它是用 Microsoft 工具链编译的,不会用 GCC 编译。目标是更改/更新它以使其在 Cygwin 下尽可能好地运行 - 而无需实际链接针对任何 Cygwin DLL。我只能合理地为 Windows 分发一个可执行文件,而不是两个。)

最佳答案

If I could link against cygwin1.dll, I could maybe somehow use its isatty(), but I can't link against that, since many of my users don't (and won't) have Cygwin installed. (And I'm not at all convinced that'd work even if it was possible.)

好的,您不能静态链接到该 DLL,但这并不意味着您不能尝试动态加载它。

您可以尝试LoadLibrary("cygwin1.dll")。如果失败,那么它没有在 cygwin 下运行,您可以使用 native Windows 函数来检测控制台类型。

另一方面,如果您可以打开该库(这意味着 Cygwin 在当前系统中可用),那么您就可以动态调用 isatty() 并使用结果以查看输出是否被重定向。

编辑:加载 cygwin DLL 并调用函数并不容易,您需要先初始化库,如本 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_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;
}

关于c - 我如何与 Cygwin 相处融洽?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45223868/

相关文章:

windows - 在Windows上解压缩.tar.gz文件

bash - 简单查找并用 sed 替换

bash - 将多词参数传递给 bash 函数

c - 数据包嗅探器 : IP Header, 服务类型在 C 中输出 0

c++ - 从这些字符串的图像中提取字符串?

java - 将自定义 uri 方案与适用于 Windows 的 Java 自包含应用程序相关联

Windows 上的 python psutil 拒绝访问

c - 如何在具有唯一元素的微型数组中尽快找到匹配元素?

在 C 中创建指向结构的动态指针数组

linux - Linux中用于获取文件日期的脚本