2012-08-11 129 views
1

我特林去捕捉在特定時刻在命令提示符(cmd窗口)顯示的信息,並將其發送到一個文本文件中。如何在Windows中隨時捕獲命令提示符的顯示輸出?

我在C/C++應用程序由批處理腳本推出這樣的:

c:\myProgramInC.exe 
echo "Ending with error" 
PAUSE 

myProgramInC.exe始終運行(與無限循環),所以如果我的腳本獲取到echo命令這意味着我的應用以異常結束。

我想得到的是腳本結束執行前的前幾行,因爲我的myProgramInC.exe總是打印有關正在發生的事情的信息,查看發生錯誤時發生了什麼會非常有用。這樣

c:\myProgramInC.exe 
**** Execution of process to get te previous N lines in the command prompt **** 
echo "Ending with error" 
PAUSE 

我知道cmd窗口的東西有一個緩衝區,我一直在想捕捉到所有的數據從這樣的緩衝。有什麼方法可以將這些信息作爲文本存儲在文件中?

我一直在嘗試一些更專業的事情,使用ProcDump創建內存轉儲,但由於我有不同的myProgramInC.exe同時運行(每個存儲在不同的位置),我只是得到消息「多個進程匹配指定的名稱。」其餘的選項對我來說沒有用,因爲我的應用程序沒有反應遲鈍,它只是結束。

任何想法?我們能夠立刻在民德

+0

是'myProgramInC.exe'你的程序?你可以添加一些日誌到你的代碼? – aphoria 2012-08-12 14:21:18

+0

'myProgramInC.exe'不是我的,但我經常更新;當發生這種情況時,我使用try-catch funcionality來獲取正在使用的數據,並且一切正常。但是,正如我所說,同一個應用程序有很多實例(它存在於不同的版本中),並且由於它是一個傳統軟件,其中一些是ANSI C代碼,它不接受try-catch的使用,並且對於這些版本有必要有某種記錄器。 – AdamC 2012-08-14 00:44:18

回答

1

您可以在C做到這一點很容易不夠,使用ReadConsoleOutputCharacter功能。

+0

我會看看這個功能,也許它會是最好的選擇。我會告訴你,如果這在星期一工作回來工作。 – AdamC 2012-08-12 07:00:42

0

有一件事是你重定向命令行輸出到文件:

c:\myProgramInC.exe >> myProgramInC.log 

然後就可以看到什麼是在日誌文件中。

+0

謝謝artpet,但這不是一個選項,因爲我的應用程序一直在磁盤上寫,它是一個關鍵的時間響應程序,除了它的許多實例,有大約30個程序一直寫到磁盤將是非常壓力的服務器資源。這就是爲什麼它只能在必要時纔在磁盤上寫下來的原因。 – AdamC 2012-08-11 02:57:09

+0

什麼是您需要捕獲程序輸出的確切時刻?它是一個特定的字符串還是一些超時? 此外,procdump接受正在運行的程序而不是名稱的PId。您可以使用Sysinternals的Windows任務管理器或Process Explorer工具來獲取Process Id。 – artapet 2012-08-11 06:31:28

+0

我需要捕捉我的應用程序打印的最後一行。它顯示了它正在處理的信息,我可以做一些分析來嘗試解決問題。實際上,大部分時間只是數組溢出的問題,但由於我的應用程序使用外部應用程序提供的信息,因此我很容易發現我的應用程序因爲提供給它的錯誤信息而出現異常。 – AdamC 2012-08-12 06:54:13

2

快速伎倆是在for /f上下文中執行,你甚至都不需要一個批處理文件,你可以從CMD行直接執行:
for /f "tokens=*" %F in ('c:\myProgramInC.exe') do @echo %F >>myPrograminC.log

這將抑制所有輸出,直到你的程序異常終止然後纔會將所有消息寫入文件。如果您的應用程序很少寫入日誌消息(或快速失敗:-)),它應該可以工作。我用10000行測試了它。下面的批處理代碼基於相同的想法 - 請注意,即使它只寫5最後一行,它仍然必須掃描所有,所以我不知道它比上述1班輪更好。

@echo off 
setlocal 

for /f "tokens=*" %%P in ('c:\myProgramInC.exe') do (
for /L %%C in (4,-1,1) do (
    set /A next=%%C+1 
    call set line_%%next%%=%%line_%%C%% 
) 
set line_1=%%P 
) 
echo program ended abnormally! %date% %time% 
for /L %%C in (5,-1,1) do call echo %%line_%%C%% 
+0

我喜歡第一個選項wmz,但我不知道這是否會影響時間響應,因爲它會有另一個運行我的應用程序的命令提示符(FOR循環)的背景實例。但既然它可能是一個快速的伎倆,值得一試。 – AdamC 2012-08-12 07:10:23

+0

我已經證明了這個選項,並且有一個不方便的地方,根據需要它沒有用處。輸出從不顯示,重要的是要看到它,因爲它是一個指示器,表示所有工作正在進行......或不是。它甚至沒有顯示出發生異常時有必要結束腳本。 – AdamC 2012-08-14 00:32:39

1

行,有可能是一個更優雅的方式來做到這一點,但是這將工作假設你有PowerShell的。

創建一個名爲Get-ConsoleAsText.ps1包含下面的腳本PowerShell腳本文件。 注意,我沒有創建這個腳本。我發現它在Windows PowerShell Blog - Capture console screen

################################################################################################################# 
# Get-ConsoleAsText.ps1 
# 
# The script captures console screen buffer up to the current cursor position and returns it in plain text format. 
# 
# Returns: ASCII-encoded string. 
# 
# Example: 
# 
# $textFileName = "$env:temp\ConsoleBuffer.txt" 
# .\Get-ConsoleAsText | out-file $textFileName -encoding ascii 
# $null = [System.Diagnostics.Process]::Start("$textFileName") 
# 

# Check the host name and exit if the host is not the Windows PowerShell console host. 
if ($host.Name -ne 'ConsoleHost') 
{ 
    write-host -ForegroundColor Red "This script runs only in the console host. You cannot run this script in $($host.Name)." 
    exit -1 
} 

# Initialize string builder. 
$textBuilder = new-object system.text.stringbuilder 

# Grab the console screen buffer contents using the Host console API. 
$bufferWidth = $host.ui.rawui.BufferSize.Width 
$bufferHeight = $host.ui.rawui.CursorPosition.Y 
$rec = new-object System.Management.Automation.Host.Rectangle 0, 0, ($bufferWidth), $bufferHeight 
$buffer = $host.ui.rawui.GetBufferContents($rec) 

# Iterate through the lines in the console buffer. 
for($i = 0; $i -lt $bufferHeight; $i++) 
{ 
    for($j = 0; $j -lt $bufferWidth; $j++) 
    { 
    $cell = $buffer[$i, $j] 
    $null = $textBuilder.Append($cell.Character) 
    } 
    $null = $textBuilder.Append("`r`n") 
} 

return $textBuilder.ToString() 

如果你本身調用PowerShell腳本,它會讀取控制檯緩衝區,並把它寫回屏幕

PowerShell -noprofile -sta -command "C:\Scripts\Get-ConsoleAsText.ps1" 

您也可以這樣調用捕捉的內容到一個文件:

PowerShell -noprofile -sta -command "C:\Scripts\Get-ConsoleAsText.ps1 | Out-File MyOutput.txt -encoding ascii" 

如果你要處理它,並執行批處理文件中的一些動作,你可以把它和處理使用FOR命令的輸出。我會把這個練習留給你。

因此,舉例來說,您的批處理文件看起來像這樣的控制檯輸出捕獲到文件:

c:\myProgramInC.exe 
echo "Ending with error" 
PowerShell -noprofile -sta -command "C:\Scripts\Get-ConsoleAsText.ps1 | Out-File MyOutput.txt -encoding ascii" 
PAUSE 
1

最後,這是我所得到的,使其工作。遵循Harry Johnston的建議 我搜索了ReadConsoleOutputCharacter函數的工作方式,並且我運行了下一個程序。

#include "stdafx.h" 
#include <iostream> 
#include <windows.h> 
#include <fstream> 

#define BUFFER_SIZE 50000 


int main(){ 
    HANDLE hOut; 
    COORD location = {0, 0}; 
    char *buffer=NULL; 
    DWORD numberRead; 
    std::ofstream fileLog; 

    buffer = new TCHAR[BUFFER_SIZE]; 

    if (buffer==NULL) 
    { 
     printf("\nError: memory could not be allocated.\n"); 
     return 1; 
    } 

    fileLog.open ("logger.txt"); 

    if (fileLog.fail()) 
    { 
     printf("\nError: file could not be opened.\n"); 
     return 1; 
    } 

    hOut = GetStdHandle(STD_OUTPUT_HANDLE); 

    ReadConsoleOutputCharacter(hOut, buffer, BUFFER_SIZE, location, &numberRead); 

    fileLog << buffer ; 

    free(buffer); 
    fileLog.close(); 

    return 0; 
} 

許多代碼,我發現它在互聯網和現在我沒有URL(除了它從另一個論壇現場的,我不知道這是否是確定以使競爭對手的網站引用),但在谷歌單一搜索不會很難找到它。

我添加了寫入文件和分配內存的部分。它運行完美VS C++ 6.

這對我來說很好,但可能會更好。兩件事情是不是很漂亮像

  1. 它寫出所有的內容從緩衝區中的文件,但它不保存新行,所以我得到一個文本文件,在一個單獨的行中的所有信息。
  2. 無法定義要捕獲多少行。它只需要從緩衝區的初始位置到程序開始的所有地方,這並不壞,但由於這個應用程序應該運行在不同的服務器上,每個服務器對於每組命令提示符窗口都有不同的緩衝區,效率並不高只是在某些情況下緩衝區較小時才使用50000字節的緩衝區。我認爲這可能很多,但由於它是實時分配的,所以使用盡可能多的內存並不是錯誤的。
0

如果有任何錯誤消息要報告回命令輸出流,則可以通過重定向運算符輕鬆地重定向到STDOUT(標準輸出)和STDERR(標準錯誤)。根據您是否要捕獲輸出和/或錯誤,取決於您。更可能的,你正在尋找的東西,如:

  • 命令2 >>文件名

「2」是重定向操作的一部分,並表示標準錯誤將被重定向,並追加到文件名。

來源,實例和文檔:

  1. http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/redirection.mspx
  2. http://ss64.com/nt/syntax-redirection.html
相關問題