How can I check if my program's stdout
has been redirected to NUL
?
That way I can avoid outputting data since it's pointless.
I mainly need this for Windows, but if you have a Linux solution, it might be helpful for others in the future, so feel free to post that as well.
There are probably other ways to do this (and it wouldn't be a surprise if there turns out to be a proper function for it I've overlooked), but here's one way:
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;
}
I figured it out myself. It's annoying.
#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);
}