控制台程序问题(200分)

  • 主题发起人 主题发起人 xh1996001
  • 开始时间 开始时间
X

xh1996001

Unregistered / Unconfirmed
GUEST, unregistred user!
在用delphi写控制台程序时,如何获取控制台的输出内容
 
我知道一个Output的全局变量保存这些输出,但它是只能写的,无法读
 
给个例子研究研究吧:<br>来自 :pitts 时间 :2000-11-6 21:15:00 <br>一个控制台程序,读一个二进制文件,处理后,向屏幕输出。。。 <br>关键的问题就是:如何向控制台输出流??? <br>搞不定啊:((( &nbsp;<br><br>来自 :xiao.lit 时间 :2000-11-06 21:18:00 <br>cout &lt;&lt; "haha just kidding" &lt;&lt; endl; <br><br>我想 write 和 writeln 应该可以的吧 &nbsp;<br><br>来自 :pitts 时间 :2000-11-06 21:29:00 <br>是 Delphi 的 {$APPTYPE CONSOLE} 控制台程序... <br>用 Write 不能写流,错误为:illegal type in Write/Writeln statement ... <br>想用 WriteConsole 试一试可是不会用:( <br><br>&nbsp;<br><br>来自 :花花公子 时间 :2000-11-06 21:39:00 <br>BOOL WriteConsole( <br>HANDLE hConsoleOutput, // handle to screen buffer <br>CONST VOID *lpBuffer, // write buffer <br>DWORD nNumberOfCharsToWrite, // number of characters to write <br>LPDWORD lpNumberOfCharsWritten, // number of characters written <br>LPVOID lpReserved // reserved <br>); <br>这个API函数可以高定!注意是控制台程序,不是简单的C/c++程序 <br>下面这个小程序在至于MSDN <br>#include &lt;windows.h&gt; <br><br>void NewLine(void); <br>void ScrollScreenBuffer(HANDLE, INT); <br><br>HANDLE hStdout, hStdin; <br>CONSOLE_SCREEN_BUFFER_INFO csbiInfo; <br><br>void main(void) <br>{ <br>LPSTR lpszPrompt1 = "Type something and press Enter:/n"; <br>LPSTR lpszPrompt2 = "Type any key: "; <br>CHAR chBuffer[256]; <br>DWORD cRead, cWritten, fdwMode, fdwOldMode; <br>WORD wOldColorAttrs; <br><br>// Get handles to STDIN and STDOUT. <br><br>hStdin = GetStdHandle(STD_INPUT_HANDLE); <br>hStdout = GetStdHandle(STD_OUTPUT_HANDLE); <br>if (hStdin == INVALID_HANDLE_VALUE || <br>hStdout == INVALID_HANDLE_VALUE) <br>{ <br>MyErrorExit("GetStdHandle"); <br>} <br><br>// Save the current text colors. <br><br>if (! GetConsoleScreenBufferInfo(hStdout, &amp;csbiInfo)) <br>MyErrorExit("GetConsoleScreenBufferInfo"); <br><br>wOldColorAttrs = csbiInfo.wAttributes; <br><br>// Set the text attr. to draw red text on black background. <br><br>if (! SetConsoleTextAttribute(hStdout, FOREGROUND_RED)) <br>MyErrorExit("SetConsoleTextAttribute"); <br><br>// Write to STDOUT and read from STDIN by using the default <br>// modes. Input is echoed automatically, and ReadFile <br>// does not return until a carriage return is typed. <br>// <br>// The default input modes are line, processed, and echo. <br>// The default output modes are processed and wrap at EOL. <br><br>while (1) <br>{ <br>if (! WriteFile( <br>hStdout, // output handle <br>lpszPrompt1, // prompt string <br>lstrlen(lpszPrompt1), // string length <br>&amp;cWritten, // bytes written <br>NULL) ) // not overlapped <br>break; <br>if (! ReadFile( <br>hStdin, // input handle <br>chBuffer, // buffer to read into <br>255, // size of buffer <br>&amp;cRead, // actual bytes read <br>NULL) ) // not overlapped <br>break; <br>if (chBuffer[0] == 'q') break; <br>} <br><br>// Turn off the line input mode, and echo the input mode. <br><br>if (! GetConsoleMode(hStdin, &amp;fdwOldMode)) <br>MyErrorExit("GetConsoleMode"); <br><br>fdwMode = fdwOldMode &amp; <br>~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT); <br>if (! SetConsoleMode(hStdin, fdwMode)) <br>MyErrorExit("SetConsoleMode"); <br><br>// Prompt for input. <br><br>if (! WriteFile( <br>hStdout, // output handle <br>lpszPrompt2, // prompt string <br>lstrlen(lpszPrompt2), // string length <br>&amp;cWritten, // bytes written <br>NULL) ) // not overlapped <br>MyErrorExit("WriteFile"); <br><br>// Without line and echo input modes, ReadFile returns <br>// when any input is available. Carriage returns must <br>// be handled, and WriteFile is used to echo input. <br><br>while (1) <br>{ <br>if (! ReadFile(hStdin, chBuffer, 1, &amp;cRead, NULL)) <br>break; <br>if (chBuffer[0] == '/r') <br>NewLine(); <br>else if (! WriteFile(hStdout, chBuffer, cRead, <br>&amp;cWritten, NULL)) break; <br>if (chBuffer[0] == 'q') break; <br>} <br><br>// Restore the original console mode. <br><br>if (! SetConsoleMode(hStdin, fdwOldMode)) <br>MyErrorExit("SetConsoleMode"); <br><br>// Restore the original text colors. <br><br>if (! SetConsoleTextAttribute(hStdout, wOldColorAttrs)) <br>MyErrorExit("SetConsoleTextAttribute"); <br>} <br><br>// The NewLine function handles carriage returns when the processed <br>// input mode is disabled. It gets the current cursor position <br>// and resets it to the first cell of the next row. <br><br>void NewLine(void) <br>{ <br>if (! GetConsoleScreenBufferInfo(hStdout, &amp;csbiInfo)) <br>MyErrorExit("GetConsoleScreenBufferInfo"); <br>csbiInfo.dwCursorPosition.X = 0; <br><br>// If it is the last line in the screen buffer, scroll <br>// the buffer up. <br><br>if ((csbiInfo.dwSize.Y-1) == csbiInfo.dwCursorPosition.Y) <br>{ <br>ScrollScreenBuffer(hStdout, 1); <br>} <br><br>// Otherwise, advance the cursor to the next line. <br><br>else csbiInfo.dwCursorPosition.Y += 1; <br><br>if (! SetConsoleCursorPosition(hStdout, <br>csbiInfo.dwCursorPosition)) <br>{ <br>MyErrorExit("SetConsoleCursorPosition"); <br>} <br>} <br>&nbsp;<br><br>来自 :pitts 时间 :2000-11-07 19:56:00 <br>再简单说一下问题吧: <br><br>Delphi 写控制台程序,已知一个 TMemoryStream ,如何将其输出到控制台窗口(Dos)? <br><br>有 API WriteConsole 可以利用,但是不会用啊,好笨啊偶:(((( <br><br>The WriteConsole function writes a character string to a console screen buffer beginning at the current cursor location. <br><br>BOOL WriteConsole( <br><br>HANDLE hConsoleOutput, // handle to a console screen buffer <br>CONST VOID *lpBuffer, // pointer to buffer to write from <br>DWORD nNumberOfCharsToWrite, // number of characters to write <br>LPDWORD lpNumberOfCharsWritten, // pointer to number of characters written <br>LPVOID lpReserved // reserved <br>); <br><br><br>Parameters <br><br>hConsoleOutput <br><br>Identifies the console screen buffer to be written to. The handle must have GENERIC_WRITE access. <br><br>lpBuffer <br><br>Points to a buffer that contains characters to be written to the screen buffer. <br><br>nNumberOfCharsToWrite <br><br>Specifies the number of characters to write. <br><br>lpNumberOfCharsWritten <br><br>Points to a 32-bit variable that receives the number of characters actually written. <br><br>lpReserved <br><br>Reserved; must be NULL. <br><br><br><br>Return Values <br><br>If the function succeeds, the return value is nonzero. <br>If the function fails, the return value is zero. To get extended error information, call GetLastError. <br><br>Remarks <br><br>WriteConsole writes characters to a console screen buffer. It behaves like the WriteFile function, except it can write in either Unicode (wide-character) or ANSI mode. To create an application that maintains a single set of sources compatible with both modes, use WriteConsole rather than WriteFile. Although WriteConsole can be used only with a console screen buffer handle, WriteFile can be used with other handles (such as files or pipes). WriteConsole fails if used with a standard handle that has been redirected to be something other than a console handle. &nbsp;<br><br>来自 :pitts 时间 :2000-11-09 20:13:00 <br>后来有人很简单就搞定了。。。 <br><br>program ShowStream; <br>{$APPTYPE CONSOLE} <br>uses <br>Windows, <br>SysUtils, <br>Classes; <br>var <br>sIn: TFileStream; <br>sOut: THandleStream; <br>begin <br>sIn := TFileStream.Create('f:/music1.gif', fmOpenRead); <br>try <br>sOut := THandleStream.Create(GetStdHandle(STD_OUTPUT_HANDLE)); <br>try <br>sOut.CopyFrom(sIn, sIn.Size); <br>finally <br>sOut.Free; <br>end; <br>finally <br>sIn.Free; <br>end; <br>end. <br>&nbsp;<br><br>来自 :pitts 时间 :2000-11-09 20:19:00 <br>多人接受答案了。 &nbsp;<br>
 
帖一段。<br>高级I/O操作:读输入事件<br><br><br>&nbsp; &nbsp; 用基本I/O例程就可以读写控制台数据。不过,因为控制台只是一种特殊的窗口,我们可以用其它API调用来操作这个窗口,接收控制台输入(包括鼠标输入)。在这个部分,我们将讨论不用Readln,从较底层接收控制台键盘和鼠标输入。<br><br><br><br>&nbsp; &nbsp; Windows可以识别两种层次的控制台I/O。上面的部分已经看到"较高层次"的控制台I/O,这种类型的控制台输入API调用是:<br>&nbsp; &nbsp; function ReadFile(hFile: THandle; var Buffer; nNumberOfBytesToRead: DWORD;<br>&nbsp; &nbsp; &nbsp; &nbsp; var lpNumberOfBytesRead: DWORD; lpOverlapped: POverlapped): BOOL; stdcall;<br>&nbsp; &nbsp; function ReadConsole(hConsoleInput: THandle; lpBuffer: Pointer; nNumberOfCharsToRead: DWORD;<br>&nbsp; &nbsp; &nbsp; &nbsp; var lpNumberOfCharsRead: DWORD; lpReserved: Pointer):BOOL; stdcall;<br><br><br><br>&nbsp; &nbsp; 在控制台窗口中使用上面两个函数效果基本一样。不同的是ReadConsole能从控制台读入Unicode字符,而ReadFile可以用于非控制台操作,比如可能重定向到标准输入的文件、内存操作。控制台根据当前代码页判断输入的是ANSI还是Unicode字符,这个问题我们稍后讨论。除非你需要读Unicode数据,否则就使用Readln。它映射到ReadFile,能够正确地操作重定向了的输入。<br><br><br><br>&nbsp; &nbsp; 可以注意到,两个函数都需要文件句柄作为参数。可以用GetStdHandle从控制台得到参数句柄。实际上,所有这些API调用都需要传入控制台句柄,要么是输入缓冲句柄,要么是输出缓冲句柄。<br><br><br><br>&nbsp; &nbsp; 为了更全面地控制控制台输入,也可以用"底层"输入的方法,这种方法在控制台事件队列中设置一个钩子。事件队列和Windows消息队列差不多,不过是接收输入事件,而非消息。在控制"底层"控制台输入时,可以用以下五个关键的API函数:<br>&nbsp; &nbsp; function ReadConsoleInput(hConsoleInput: THandle; var lpBuffer: TInputRecord; nLength: DWORD;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;var lpNumberOfEventsRead: DWORD): BOOL; stdcall;<br>&nbsp; &nbsp; function WriteConsoleInput(hConsoleInput: THandle; const lpBuffer: TInputRecord; nLength: DWORD;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;var lpNumberOfEventsWritten: DWORD): BOOL; stdcall;<br>&nbsp; &nbsp; function PeekConsoleInput(hConsoleInput: THandle; var lpBuffer: TInputRecord; nLength: DWORD;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;var lpNumberOfEventsRead: DWORD): BOOL; stdcall;<br>&nbsp; &nbsp; function GetNumberOfConsoleInputEvents(hConsoleInput: THandle; var lpNumberOfEvents: DWORD):<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;BOOL; stdcall;<br>&nbsp; &nbsp; function FlushConsoleInputBuffer(hConsoleInput: THandle): BOOL; stdcall;<br>&nbsp; &nbsp; &nbsp; &nbsp; hConsoleInput参数是API调用的返回值。<br>&nbsp; &nbsp; GetStdHandle(STD_INPUT_HANDLE)<br><br><br><br>&nbsp; &nbsp; 其它的参数可以见其名而知其意,不再赘述。唯一要注意的是TinputRecord类型。TinputRecord是INPUT_RECORD结构的Delphi别名。这个结构其实是五种输入事件类型的集合。第一个字段,EventType,指明后面跟着的是何种事件记录类型。在MSDN上有事件类型的详细信息。我们最关心的是鼠标和键盘事件。另外三种用得较少的事件类型是:<br><br><br><br>&nbsp; &nbsp; * WINDOW_BUFFER_SIZE_EVENT 屏幕大小改变时发出 <br><br><br>&nbsp; &nbsp; * MENU_EVENT 用户使用控制台菜单或工具栏时发出 <br><br><br>&nbsp; &nbsp; * FOCUS_EVENT 控制台得到输入焦点时发出<br><br><br><br>&nbsp; &nbsp; WINDOW_BUFFER_SIZE事件很不常用,因为一般而言用户不会主动去改变控制台窗口大小。WINDOW_BUFFER_SIZE事件之发生于某些特定的控制台模式,且常常用于重画屏幕。另外两个事件,MENU_EVENT和FOCUS_EVENT由Windows内部使用,基本找不到相关文档资料。微软甚至建议应该"忽略它们"。<br><br><br><br>&nbsp; &nbsp; 如果控制台处在活动状态,当一个键被按下时,就激发KEY_EVENT事件。普通的字母、数字等可打印键和Shift/Ctrl、功能键等都是如此,类似于WM_KEYPRESS事件。在KEY_EVENT_RECORD类型中,可以包括以下数据:<br><br>* bKeyDown 如果有键被按下,则为真;被释放则为假。 <br>* wRepeatCount 在一行里的击键次数。 <br>* wVirtualKeyCode 按键的虚拟键码。<br>* wVirtualScanCode 键盘扫描码。 <br>* UnicodeChar 按下的Unicode字符。<br>* AsciiChar 按下的ASCII字符。<br>* dwControlKeyState 控制键状态。 <br><br><br><br>&nbsp; &nbsp; 当控制台处于正确的模式(缺省状态),在屏幕缓冲上产生鼠标事件时,激发MOUSE_EVENT事件。接受到的数据记录包括以下信息:<br><br>* dwMousePosition 事件发生时鼠标的坐标。<br>* dwButtonState 按下的鼠标键的位掩码。<br>* dwControlKeyState 控制键状态。<br>* dwEventFlags 事件类型。<br><br><br><br>&nbsp; &nbsp; 比较难以理解的是鼠标键位掩码。它包括了32个可按下的鼠标键位置。一般人不会用到32键鼠标,所以只有前五个键被预定义为常量。对于典型的三键鼠标,要用到的常量是:<br><br>* FROM_LEFT_1ST_BUTTON_PRESSED <br>* RIGHTMOST_BUTTON_PRESSED <br>* FROM_LEFT_2ND_BUTTON_PRESSED<br><br><br><br>&nbsp; &nbsp; 这三个变量对应于三个DWORD值,循序分别为:左、右、左边第二个。<br><br><br><br>&nbsp; &nbsp; 下面的代码段展示了如何截获键盘和鼠标事件。程序开始运行时,会发生一些很有意思的事。首先,注意[Ctrl][C]组合键,按下这两个键,程序会结束。Windows安装了一个内部击键句柄,[Ctrl][C]和[Ctrl][Break]都会导致程序结束。<br><br>{$APPTYPE CONSOLE}<br>program ConsoleInput;<br>uses Windows;<br>var<br>&nbsp; hInput: THandle;<br>&nbsp; arrInputRecs: array[0..9] of TInputRecord;<br>&nbsp; dwCur, dwCount: DWORD;<br>&nbsp; cCur: Char;<br>&nbsp; coorCur: TCoord;<br>begin<br>&nbsp; hInput := GetStdHandle(STD_INPUT_HANDLE);<br>&nbsp; while True do begin<br>&nbsp; &nbsp; ReadConsoleInput(hInput, arrInputRecs[0], 10, dwCount);<br>&nbsp; &nbsp; &nbsp;for dwCur := 0 to 10 - 1 do<br>&nbsp; &nbsp; &nbsp; &nbsp;case arrInputRecs[dwCur].EventType of<br>&nbsp; &nbsp; &nbsp; &nbsp; KEY_EVENT:<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; with arrInputRecs[dwCur].Event.KeyEvent do begin<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cCur := AsciiChar;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if cCur = '' then<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if bKeyDown then<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Writeln('按下了不可打印键。')<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;else<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Writeln('松开了不可打印键。')<br>&nbsp; //你也可以用wVirtualKeyCode取得功能键码,F1是112,以此类推。<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if bKeyDown then<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Writeln('按下 ', cCur, ' ',<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; wRepeatCount, ' 次。')<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Writeln('松开 ', cCur, ' 键。');<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; &nbsp; &nbsp; { 为避免与WINDOWS的mouse_event函数冲突,Delphi重命名了MOUSE_EVENT事件。}<br>&nbsp; &nbsp; &nbsp; &nbsp; _MOUSE_EVENT:<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; with arrInputRecs[dwCur].Event.MouseEvent do<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;coorCur := dwMousePosition;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if dwEventFlags = 0 then<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Writeln('鼠标键按下,坐标:', coorCur.X,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ',', coorCur.Y);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; &nbsp; &nbsp;end; // case<br>&nbsp; &nbsp;end; // while<br>end.<br><br><br><br>&nbsp; &nbsp; 在程序刚开始运行时,偶尔会看到"键"这个字符串显示出来。这是因为程序一开始运行,[Enter]键就被释放。字符串'松开了' + #13 + '键。' 被打印出来。<br><br><br><br>&nbsp; &nbsp; 最后要注意的一点是,有关KEY_EVENT_RECORD类型的文档指出,按下/松开[Alt]键而没有同时按下其它键,不会引发输入事件。但是,我们的示例程序却表明文档资料不正确。按下[Alt]键同样会引发输入事件。<br><br>
 
看不太懂。<br>我现在是使用Writeln向控制台输出了文字<br>在控制台程序执行完后我要将在控制台上输出的文字保存<br>所以要获取前面已经输出的文字
 
我也沒做過,我這裡有這篇文章的全文。都帖上來太長了。<br>怎麼發給你。
 
hxie@wind.com.cn<br>谢谢
 
我没明白!!delphi控制台和其它控制台一样,你写什么就显示什么,怎么?你写也什么而不知道读回什么了?还是还要执行其它程序,要得到其它程序的执行结果??<br>你用Writeln向控制台输出了文字时,先把输出的文字保存为变量,然后用WRITELN 这个变量就行了,<br>如果你要得到其它程序的执行结果,那就要拦截屏幕输出了,具体怎么做我也不知
 
to zhksoft:如果控制台程序每做一件事都输出一些内容,那么我不是要每次都记住自己写了些什么;这个我也知道,这是个我认为最笨的办法,而且不能保证不漏掉。<br>为什么不能到最后将在控制台上输出的内容都得到再保存呢?
 
已發出,注意查收
 
樓主,如果那個文件打不開,可以到這裡看。<br>http://www.codelphi.com/
 
后退
顶部