2017-08-21 5 views
1

Dans le programme suivant imprimer à la console en utilisant deux fonctions différentesPourquoi ne puis-je pas rediriger la sortie de 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); 
} 

Si quand j'exécute ce programme et réoriente sa sortie en utilisant a > out.txt ou a 1> out.txt rien est imprimé à la console (comme prévu), mais le contenu out.txt ne sont

WriteFile 

ce qui est différent entre les deux qui permet d'appeler WriteFile être redirigé vers le fichier et les appels à WriteConsole pour aller ... nulle part

testé avec gcc et msvc sur les fenêtres 10

+4

* WriteConsole échoue si elle est utilisée avec une poignée standard qui est redirigé vers un fichier * – RbMm

+0

@RbMm où est ça? – rtpax

+0

from msdn - https://docs.microsoft.com/en-us/windows/console/writeconsole – RbMm

Répondre

4

WriteConsole Fonctionne uniquement avec des poignées d'écran de la console, et non pas les fichiers ni tuyaux.

Si vous écrivez uniquement du contenu ASCII, vous pouvez utiliser WriteFile pour tout.

Si vous devez écrire des caractères Unicode, vous pouvez utiliser GetConsoleMode pour détecter le type de handle, il échoue pour tout ce qui n'est pas un handle de console. Lorsque vous effectuez une sortie brute comme celle-ci, vous devez également gérer le BOM si le handle est redirigé vers un fichier.

This blog post est un bon point de départ pour traiter Unicode dans la console Windows ...

+1

Spécifiquement, dans Windows 8+ 'WriteConsole' demande un contrôle d'E/S (IOCTL) qui est seulement pris en charge par le périphérique de la console ConDrv. Un autre périphérique, tel qu'un système de fichiers, ne remplira pas cet IOCTL en tant que paramètre non valide. À son tour, l'API de la console le signalera comme un handle non valide. Dans Windows 7 et versions antérieures, l'API console utilise LPC au lieu du périphérique ConDrv. Les poignées de la mémoire tampon sont donc signalées pour le routage vers la connexion LPC et donc immédiatement détectables en mode utilisateur (par l'API, * not * code client) en vérifiant que les deux bits inférieurs sont définis (par exemple 3, 7, 11, etc.). – eryksun

+1

Cet ancien article de blog contient des informations utiles, mais cela n'aide pas quand il confond la console avec le shell CMD. – eryksun

0

Le code ci-dessous peut être utilisé pour rediriger la sortie de la console si l'autre partie utilise WriteConsole. Le code lit la sortie via un tampon d'écran de console caché. J'ai écrit ce code pour intercepter la sortie de débogage des pilotes DirectShow écrivent sur la console. Directshow pilotes ont l'habitude de faire des choses que les conducteurs ne devraient pas faire, comme l'écriture de fichiers journaux indésirables, l'écriture sur la console et le plantage.

// 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; 
}