2017-08-21 54 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; 
} 
相關問題