2012-08-11 130 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
相关问题