2017-08-21 52 views
1

在下面的程序中,我使用两种不同的功能为什么我不能从WriteConsole重定向输出?

#include <windows.h> 

int main() { 
    HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); 
    DWORD byteswritten; 
    WriteConsole(h, "WriteConsole", 12, &byteswritten, NULL); 
    WriteFile(h, "WriteFile", 9, &byteswritten, NULL); 
} 

如果当我执行这个程序并重定向它的使用a > out.txta 1> out.txt没有东西打印到控制台(预期)输出打印到控制台,但内容out.txt

WriteFile 

什么是允许调用WriteFile两个被重定向到文件,并呼吁WriteConsole之间不同的去...无处

测试与海湾合作委员会和MSVC在Windows 10

+4

* WriteConsole如果与被重定向到一个文件* – RbMm

+0

@RbMm标准手柄使用失败何方而来? – rtpax

+0

从MSDN - https://docs.microsoft.com/en-us/windows/console/writeconsole – RbMm

回答

4

WriteConsole只与控制台屏幕句柄,而不是文件也不管道工程。

如果你只写ASCII内容,您可以使用WriteFile的一切。

如果你需要写,你可以使用GetConsoleMode检测手柄式Unicode字符,它失败了,是不是一个控制台处理一切。

在做这样你还必须应对BOM如果手柄被重定向到一个文件的原始输出。

This blog post是使用Unicode在Windows控制台处理一个很好的起点......

+1

具体来说,在Windows 8+'WriteConsole'要求的I/O控制(IOCTL)是唯一由ConDrv控制台设备的支持。某些其他设备(如文件系统)会将此IOCTL视为无效参数而失败,并且控制台API会将其报告为无效句柄。在Windows 7和更早版本中,控制台API使用LPC代替ConDrv设备,因此控制台缓冲区句柄被标记为路由到LPC连接,因此可立即在用户模式(通过API,*非*客户端代码)检测到低两位被设置(例如3,7,11等)。 – eryksun

+1

那篇旧的博客文章有一些有用的信息,但当它将控制台与CMD外壳混淆时,这无关紧要。 – eryksun

0

下面的代码可以用来重定向控制台输出,如果对方使用WriteConsole。代码通过隐藏控制台屏幕缓冲区读取输出。我已经编写了这段代码来拦截一些directshow驱动程序写入控制台的调试输出。 Directshow驱动程序有驾驶员不应该做的事情的习惯,比如写入不需要的日志文件,写入控制台并崩溃。

// info to redirected console output 
typedef struct tagRedConInfo 
{ 
    // hidden console 
    HANDLE  hCon; 

    // old console handles 
    HANDLE  hOldConOut; 
    HANDLE  hOldConErr; 

    // buffer to read screen content 
    CHAR_INFO *BufData; 
    INT  BufSize; 

    // 
} TRedConInfo; 




//------------------------------------------------------------------------------ 
// GLOBALS 
//------------------------------------------------------------------------------ 

// initial handles 
HANDLE gv_hOldConOut; 
HANDLE gv_hOldConErr; 



//------------------------------------------------------------------------------ 
// PROTOTYPES 
//------------------------------------------------------------------------------ 

/* init redirecting the console output */ 
BOOL Shell_InitRedirectConsole(BOOL,TRedConInfo*); 

/* done redirecting the console output */ 
BOOL Shell_DoneRedirectConsole(TRedConInfo*); 

/* read string from hidden console, then clear */ 
BOOL Shell_ReadRedirectConsole(TRedConInfo*,TCHAR*,INT); 

/* clear buffer of hidden console */ 
BOOL Shell_ClearRedirectConsole(TRedConInfo*); 





//------------------------------------------------------------------------------ 
// IMPLEMENTATIONS 
//------------------------------------------------------------------------------ 


/***************************************/ 
/* init redirecting the console output */ 
/***************************************/ 

BOOL Shell_InitRedirectConsole(BOOL in_SetStdHandles, TRedConInfo *out_RcInfo) 
{ 
    /* locals */ 
    HANDLE    lv_hCon; 
    SECURITY_ATTRIBUTES lv_SecAttr; 


    // preclear structure 
    memset(out_RcInfo, 0, sizeof(TRedConInfo)); 

    // prepare inheritable handle just in case an api spans an external process 
    memset(&lv_SecAttr, 0, sizeof(SECURITY_ATTRIBUTES)); 
    lv_SecAttr.nLength  = sizeof(SECURITY_ATTRIBUTES); 
    lv_SecAttr.bInheritHandle = TRUE; 

    // create hidden console buffer 
    lv_hCon = CreateConsoleScreenBuffer(
    GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 
    &lv_SecAttr, CONSOLE_TEXTMODE_BUFFER, 0); 

    // failed to create console buffer? 
    if (lv_hCon == INVALID_HANDLE_VALUE) 
    return FALSE; 

    // store 
    out_RcInfo->hCon = lv_hCon; 

    // set as standard handles for own process? 
    if (in_SetStdHandles) 
    { 
    // mutex the globals 
    WaitForGlobalVarMutex(); 

    // remember the old handles 
    out_RcInfo->hOldConOut = GetStdHandle(STD_OUTPUT_HANDLE); 
    out_RcInfo->hOldConErr = GetStdHandle(STD_ERROR_HANDLE); 

    // set hidden console as std output 
    SetStdHandle(STD_OUTPUT_HANDLE, lv_hCon); 
    SetStdHandle(STD_ERROR_HANDLE, lv_hCon); 

    // is this the first instance? 
    if (!gv_hOldConOut) 
    { 
     // inform our own console output code about the old handles so our own 
     // console will be writing to the real console, only console output from 
     // other parties will write to the hidden console 
     gv_hOldConOut = out_RcInfo->hOldConOut; 
     gv_hOldConErr = out_RcInfo->hOldConErr; 
    } 

    // release mutex 
    ReleaseGlobalVarMutex(); 
    } 

    // done 
    return TRUE; 
} 




/***************************************/ 
/* done redirecting the console output */ 
/***************************************/ 

BOOL Shell_DoneRedirectConsole(TRedConInfo *in_RcInfo) 
{ 
    // validate 
    if (!in_RcInfo->hCon) 
    return FALSE; 

    // restore original handles? 
    if (in_RcInfo->hOldConOut) 
    { 
    // mutex the globals 
    WaitForGlobalVarMutex(); 

    // restore original handles 
    SetStdHandle(STD_OUTPUT_HANDLE, in_RcInfo->hOldConOut); 
    SetStdHandle(STD_ERROR_HANDLE, in_RcInfo->hOldConErr); 

    // was this the first instance? 
    if (in_RcInfo->hOldConOut == gv_hOldConOut) 
    { 
     // clear 
     gv_hOldConOut = NULL; 
     gv_hOldConErr = NULL; 
    } 

    // release mutex 
    ReleaseGlobalVarMutex(); 
    } 

    // close the console handle 
    CloseHandle(in_RcInfo->hCon); 

    // free read buffer 
    if (in_RcInfo->BufData) 
    MemFree(in_RcInfo->BufData); 

    // clear structure 
    memset(in_RcInfo, 0, sizeof(TRedConInfo)); 

    // done 
    return TRUE; 
} 




/***********************************************/ 
/* read string from hidden console, then clear */ 
/***********************************************/ 

BOOL Shell_ReadRedirectConsole(TRedConInfo *in_RcInfo, TCHAR *out_Str, INT in_MaxLen) 
{ 
    /* locals */ 
    TCHAR      lv_C; 
    INT      lv_X; 
    INT      lv_Y; 
    INT      lv_W; 
    INT      lv_H; 
    INT      lv_N; 
    INT      lv_Len; 
    INT      lv_Size; 
    INT      lv_PrvLen; 
    COORD      lv_DstSze; 
    COORD      lv_DstOfs; 
    DWORD      lv_Written; 
    SMALL_RECT     lv_SrcRect; 
    CHAR_INFO     *lv_BufData; 
    CONSOLE_SCREEN_BUFFER_INFO lv_Info; 


    // preclear output 
    out_Str[0] = 0; 

    // validate 
    if (!in_RcInfo->hCon) 
    return FALSE; 

    // reserve character for eos 
    --in_MaxLen; 

    // get current buffer info 
    if (!GetConsoleScreenBufferInfo(in_RcInfo->hCon, &lv_Info)) 
    return FALSE; 

    // check whether there is something at all 
    if (!lv_Info.dwSize.X || !lv_Info.dwSize.Y) 
    return FALSE; 

    // limit the buffer passed onto read call otherwise it 
    // will fail with out-of-resources error 
    lv_DstSze.X = (INT16)(lv_Info.dwSize.X); 
    lv_DstSze.Y = (INT16)(lv_Info.dwSize.Y < 8 ? lv_Info.dwSize.Y : 8); 

    // size of buffer needed 
    lv_Size = lv_DstSze.X * lv_DstSze.Y * sizeof(CHAR_INFO); 

    // is previous buffer too small? 
    if (!in_RcInfo->BufData || in_RcInfo->BufSize < lv_Size) 
    { 
    // free old buffer 
    if (in_RcInfo->BufData) 
     MemFree(in_RcInfo->BufData); 

    // allocate read buffer 
    if ((in_RcInfo->BufData = (CHAR_INFO*)MemAlloc(lv_Size)) == NULL) 
     return FALSE; 

    // store new size 
    in_RcInfo->BufSize = lv_Size; 
    } 

    // always write to (0,0) in buffer 
    lv_DstOfs.X = 0; 
    lv_DstOfs.Y = 0; 

    // init src rectangle 
    lv_SrcRect.Left = 0; 
    lv_SrcRect.Top = 0; 
    lv_SrcRect.Right = lv_DstSze.X; 
    lv_SrcRect.Bottom = lv_DstSze.Y; 

    // buffer to local 
    lv_BufData = in_RcInfo->BufData; 

    // start at first string position in output 
    lv_Len = 0; 

    // loop until no more rows to read 
    do 
    { 
    // read buffer load 
    if (!ReadConsoleOutput(in_RcInfo->hCon, lv_BufData, lv_DstSze, lv_DstOfs, &lv_SrcRect)) 
     return FALSE; 

    // w/h of actually read content 
    lv_W = lv_SrcRect.Right - lv_SrcRect.Left + 1; 
    lv_H = lv_SrcRect.Bottom - lv_SrcRect.Top + 1; 

    // remember previous position 
    lv_PrvLen = lv_Len; 

    // loop through rows of buffer 
    for (lv_Y = 0; lv_Y < lv_H; ++lv_Y) 
    { 
     // reset output position of current row 
     lv_N = 0; 

     // loop through columns 
     for (lv_X = 0; lv_X < lv_W; ++lv_X) 
     { 
     // is output full? 
     if (lv_Len + lv_N > in_MaxLen) 
      break; 

     // get character from screen buffer, ignore attributes 
     lv_C = lv_BufData[lv_Y * lv_DstSze.X + lv_X].Char.UnicodeChar; 

     // append character 
     out_Str[lv_Len + lv_N++] = lv_C; 
     } 

     // remove spaces at the end of the line 
     while (lv_N > 0 && out_Str[lv_Len+lv_N-1] == ' ') 
     --lv_N; 

     // if row was not blank 
     if (lv_N > 0) 
     { 
     // update output position 
     lv_Len += lv_N; 

     // is output not full? 
     if (lv_Len + 2 < in_MaxLen) 
     { 
      // append cr/lf 
      out_Str[lv_Len++] = '\r'; 
      out_Str[lv_Len++] = '\n'; 
     } 
     } 
    } 

    // update screen position 
    lv_SrcRect.Top = (INT16)(lv_SrcRect.Top + lv_H); 
    lv_SrcRect.Bottom = (INT16)(lv_SrcRect.Bottom + lv_H); 

    // until nothing is added or no more screen rows 
    } while (lv_PrvLen != lv_Len && lv_SrcRect.Bottom < lv_Info.dwSize.Y); 

    // remove last cr/lf 
    if (lv_Len > 2) 
    lv_Len -= 2; 

    // append eos 
    out_Str[lv_Len] = 0; 

    // total screen buffer size in characters 
    lv_Size = lv_Info.dwSize.X * lv_Info.dwSize.Y; 

    // clear the buffer with spaces 
    FillConsoleOutputCharacter(in_RcInfo->hCon, ' ', lv_Size, lv_DstOfs, &lv_Written); 

    // reset cursor position to (0,0) 
    SetConsoleCursorPosition(in_RcInfo->hCon, lv_DstOfs); 

    // done 
    return TRUE; 
} 




/**********************************/ 
/* clear buffer of hidden console */ 
/**********************************/ 

BOOL Shell_ClearRedirectConsole(TRedConInfo *in_RcInfo) 
{ 
    /* locals */ 
    INT      lv_Size; 
    COORD      lv_ClrOfs; 
    DWORD      lv_Written; 
    CONSOLE_SCREEN_BUFFER_INFO lv_Info; 


    // validate 
    if (!in_RcInfo->hCon) 
    return FALSE; 

    // get current buffer info 
    if (!GetConsoleScreenBufferInfo(in_RcInfo->hCon, &lv_Info)) 
    return FALSE; 

    // clear from (0,0) onward 
    lv_ClrOfs.X = 0; 
    lv_ClrOfs.Y = 0; 

    // total screen buffer size in characters 
    lv_Size = lv_Info.dwSize.X * lv_Info.dwSize.Y; 

    // clear the buffer with spaces 
    FillConsoleOutputCharacter(in_RcInfo->hCon, ' ', lv_Size, lv_ClrOfs, &lv_Written); 

    // reset cursor position to (0,0) 
    SetConsoleCursorPosition(in_RcInfo->hCon, lv_ClrOfs); 

    // done 
    return TRUE; 
} 
相关问题