如果stderr被重定向到stdout,请签入程序 从C++程序中,可以检查STDRR是否重定向到STDUT,反之亦然?基本上我想知道这两个文件描述符是否指向同一个地方。使用本机API的特定于平台的解决方案是可以的。

如果stderr被重定向到stdout,请签入程序 从C++程序中,可以检查STDRR是否重定向到STDUT,反之亦然?基本上我想知道这两个文件描述符是否指向同一个地方。使用本机API的特定于平台的解决方案是可以的。,c++,winapi,posix,iostream,C++,Winapi,Posix,Iostream,Linux,可能还有其他unix类:fstat同时使用fds和compare dev:ino对。Linux,可能还有其他unix类:fstat同时使用fds和compare dev:ino对。对于windows 7和更高版本的控制台句柄-这是XP上的真实文件句柄这不是真的,关于vista-不记得了。我们可以通过调用STD_OUTPUT_HANDLE和STD_ERROR_HANDLE得到这两个句柄。但接下来需要通过句柄比较文件。这不等于直接比较句柄值-因为两个不同的句柄可以指向同一个文件。即使我们

Linux,可能还有其他unix类:fstat同时使用fds和compare dev:ino对。

Linux,可能还有其他unix类:fstat同时使用fds和compare dev:ino对。

对于windows 7和更高版本的控制台句柄-这是XP上的真实文件句柄这不是真的,关于vista-不记得了。我们可以通过调用STD_OUTPUT_HANDLE和STD_ERROR_HANDLE得到这两个句柄。但接下来需要通过句柄比较文件。这不等于直接比较句柄值-因为两个不同的句柄可以指向同一个文件。即使我们从handle得到指向FILE_对象的指针,这也可能是从用户模式得到的——如果我们谈到文件系统文件,两个不同的FILE_对象可以指向同一个文件。所以我认为最好的方法是——得到两个文件的名称——并比较——它们是否相等。这可以通过以下方式完成。代码可以是这样的

NTSTATUS QueryName(HANDLE hFile, PUNICODE_STRING Name)
{
    union {
        PVOID buf;
        POBJECT_NAME_INFORMATION poni;
    };

    static volatile UCHAR guz;
    PVOID stack = alloca(guz);

    ULONG cb = 0, rcb = 512;
    NTSTATUS status;

    do 
    {
        if (cb < rcb)
        {
            cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
        }

        if (0 <= (status = ZwQueryObject(hFile, ObjectNameInformation, buf, cb, &rcb)))
        {
            return RtlDuplicateUnicodeString(0, &poni->Name, Name);
        }

    } while (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_BUFFER_OVERFLOW);

    return status;
}

NTSTATUS AreFilesTheSame(HANDLE h1, HANDLE h2, PBOOL pb)
{
    if (h1 == h2)
    {
        *pb = TRUE;
        return STATUS_SUCCESS;
    }

    if (!h1 || !h2)
    {
        *pb = FALSE;
        return STATUS_SUCCESS;
    }

    UNICODE_STRING name1, name2;
    NTSTATUS status;

    if (0 <= (status = QueryName(h1, &name1)))
    {
        if (0 <= (status = QueryName(h2, &name2)))
        {
            *pb = RtlEqualUnicodeString(&name1, &name2, TRUE);
            RtlFreeUnicodeString(&name2);
        }
        RtlFreeUnicodeString(&name1);
    }

    return status;
}

BOOL b;
AreFilesTheSame(GetStdHandle(STD_OUTPUT_HANDLE), GetStdHandle(STD_ERROR_HANDLE), &b);

但是对于xp,这将不适用于windows 7和更高版本的控制台句柄-这是xp上真正的文件句柄-这不是真的,关于vista-不记得了。我们可以通过调用STD_OUTPUT_HANDLE和STD_ERROR_HANDLE得到这两个句柄。但接下来需要通过句柄比较文件。这不等于直接比较句柄值-因为两个不同的句柄可以指向同一个文件。即使我们从handle得到指向FILE_对象的指针,这也可能是从用户模式得到的——如果我们谈到文件系统文件,两个不同的FILE_对象可以指向同一个文件。所以我认为最好的方法是——得到两个文件的名称——并比较——它们是否相等。这可以通过以下方式完成。代码可以是这样的

NTSTATUS QueryName(HANDLE hFile, PUNICODE_STRING Name)
{
    union {
        PVOID buf;
        POBJECT_NAME_INFORMATION poni;
    };

    static volatile UCHAR guz;
    PVOID stack = alloca(guz);

    ULONG cb = 0, rcb = 512;
    NTSTATUS status;

    do 
    {
        if (cb < rcb)
        {
            cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
        }

        if (0 <= (status = ZwQueryObject(hFile, ObjectNameInformation, buf, cb, &rcb)))
        {
            return RtlDuplicateUnicodeString(0, &poni->Name, Name);
        }

    } while (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_BUFFER_OVERFLOW);

    return status;
}

NTSTATUS AreFilesTheSame(HANDLE h1, HANDLE h2, PBOOL pb)
{
    if (h1 == h2)
    {
        *pb = TRUE;
        return STATUS_SUCCESS;
    }

    if (!h1 || !h2)
    {
        *pb = FALSE;
        return STATUS_SUCCESS;
    }

    UNICODE_STRING name1, name2;
    NTSTATUS status;

    if (0 <= (status = QueryName(h1, &name1)))
    {
        if (0 <= (status = QueryName(h2, &name2)))
        {
            *pb = RtlEqualUnicodeString(&name1, &name2, TRUE);
            RtlFreeUnicodeString(&name2);
        }
        RtlFreeUnicodeString(&name1);
    }

    return status;
}

BOOL b;
AreFilesTheSame(GetStdHandle(STD_OUTPUT_HANDLE), GetStdHandle(STD_ERROR_HANDLE), &b);

但对于xp,这将不起作用

这似乎适合我的需要,谢谢!现在我只需要一个Windows解决方案…这似乎适合我的需要,谢谢!现在我只需要一个Windows解决方案…尝试GetFinalPathNameByHandle。我不确定它是否适用于管道,但值得一试。@HarryJohnston在Windows 7上尝试了GetFinalPathName ByHandle,不幸的是,它不适用于GetStdHandleSTD_输出_HANDLE。失败,GetLastError返回错误\无效\句柄。请尝试GetFinalPathNameByHandle。我不确定它是否适用于管道,但值得一试。@HarryJohnston在Windows 7上尝试了GetFinalPathName ByHandle,不幸的是,它不适用于GetStdHandleSTD_输出_HANDLE。失败,GetLastError返回错误\u无效\u句柄。谢谢!我终于在Windows7上编译并链接了这段代码,但不幸的是,它没有按预期工作。即使在使用2>&1启动程序时,名称也是不同的,例如。\REGISTRY\MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execut。。。对于stdout vs.\knowndls。。。对于stderr。此代码是否按照您的要求工作?同样,当给定句柄是管道时,即当程序的输出重定向到另一个程序的输入时,NtQueryObject失败,状态为“对象路径无效”0xc0000039。@usta-\KnownDlls。。。对于stderr??注册表\MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image文件执行。。。对于stdout??你怎么搞糊涂了?谢谢!我终于在Windows7上编译并链接了这段代码,但不幸的是,它没有按预期工作。即使在使用2>&1启动程序时,名称也是不同的,例如。\REGISTRY\MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execut。。。对于stdout vs.\knowndls。。。对于stderr。此代码是否按照您的要求工作?同样,当给定句柄是管道时,即当程序的输出重定向到另一个程序的输入时,NtQueryObject失败,状态为“对象路径无效”0xc0000039。@usta-\KnownDlls。。。对于stderr??注册表\MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image文件执行。。。对于stdout??你搞不清楚最小值是多少