如何检查stdout是否已重定向到Windows上的NUL(Linux上的a.k.a./ dev / null)?

时间:2014-01-12 00:41:33

标签: c winapi visual-c++ stdout

如何检查我的程序stdout是否已重定向到NUL
这样我就可以避免输出数据,因为它毫无意义。

我主要需要这个用于Windows,但是如果你有一个Linux解决方案,它可能对将来的其他人有帮助,所以也可以随意发布。

2 个答案:

答案 0 :(得分:2)

可能有其他方法可以做到这一点(如果事实证明它是一个我忽略的适当功能也不会令人感到意外),但这是一种方式:

enum
{
    Output_Console,
    Output_File,
    Output_NUL,
};

bool GetOutputHandleType(int* piType)
{
    HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
    if (h)
    {
        BY_HANDLE_FILE_INFORMATION fi;
        if (GetFileInformationByHandle(h, &fi))
        {
            *piType = Output_File;
            return true;
        }
        if (GetLastError() == ERROR_INVALID_FUNCTION)
        {
            *piType = Output_NUL;
            return true;
        }
        if (GetLastError() == ERROR_INVALID_HANDLE)
        {
            *piType = Output_Console;
            return true;
        }
    }
    return false;
}

答案 1 :(得分:0)

我自己想通了。这很烦人。

#include <Windows.h>
#include <io.h>
#pragma comment(lib, "ntdll.lib")  // can instead use GetProcAddress (below)
extern "C" NTSTATUS __stdcall NtQueryVolumeInformationFile(
    HANDLE FileHandle, struct _IO_STATUS_BLOCK *IoStatusBlock,
    void *FsInformation, unsigned long Length,
    enum _FSINFOCLASS FsInformationClass);
bool isdevnull(FILE *file)
{
    struct FILE_FS_DEVICE_INFORMATION
    { unsigned long DeviceType, Characteristics; } fsinfo;
    struct { void *info, *status; } iosb;
    typedef NTSTATUS (__stdcall *PNTQIF)(
        HANDLE FileHandle, struct _IO_STATUS_BLOCK *IoStatusBlock,
        void *FsInformation, unsigned long Length,
        enum _FSINFOCLASS FsInformationClass);
    PNTQIF const ntqif =
        true  // True if you have ntdll.lib, false otherwise
        ? NtQueryVolumeInformationFile
        : (PNTQIF) GetProcAddress(
            GetModuleHandle(TEXT("ntdll.dll")),
            "NtQueryVolumeInformationFile");
    return ntqif(
        (HANDLE) _get_osfhandle(_fileno(stdout)),
        (struct _IO_STATUS_BLOCK *)&iosb,
        &fsinfo, sizeof(fsinfo),
        (enum _FSINFOCLASS)4
    ) == 0 && fsinfo.DeviceType == 0x00000015 /*FILE_DEVICE_NULL*/;
}
int main()
{
    bool b = isdevnull(stdout);
}