Windows控制台中的Tcl和Ctrl-C

时间:2015-01-12 13:34:27

标签: windows tcl interrupt windows-console

我在Windows Tcl 8.5应用程序中拦截Ctrl-C时遇到问题。我在我开发的扩展库中添加了一个控制台处理程序,但它并不总是有效。

如果某些Tcl代码正在执行,那么一切正常。但是如果应用程序正在等待用户输入,则按Ctrl-C会终止它。调用我的处理程序,但同时(在不同的线程中?)Tcl REPL调用Tcl_Exit。这真的搞砸了一切。

据我所知,REPL调用Tcl_Exit被调用,因为它错误地认为stdin遇到EOF。反过来,这是由于当按下Ctrl-C时,读取例程返回,并返回读取的字节数,即零。 REPL将此条件解释为EOF。

有没有简单的方法来解决这个问题?我知道我可以放弃Tcl内置通道并提供我自己的通道,但这对于这个简单的问题来说似乎有点过头了。

我尝试了twapi::set_console_control_handler,但它似乎根本不起作用。按Ctrl-C始终终止应用程序,永远不会调用处理程序。

2 个答案:

答案 0 :(得分:2)

SetConsoleCtrlHandler的MSDN文档指出单独处理CTRL_C处理,但可以通过将控制台模式设置为ENABLE_PROCESSED_INPUT来禁用此功能。然后,它将Ctrl-C事件报告为键盘输入。

以下批处理代码加载到解释器中(使用load ctrl_c.dll ctrl_c; win32::SetCtrlHandler让我拦截Control-C键盘输入而不退出:

package require critcl

namespace eval win32 {
    critcl::ccode {
#define STRICT
#define WIN32_LEAN_AND_MEAN
#define _WIN32_WINNT 0x0502
#include <windows.h>

BOOL CtrlHandler(DWORD dwEvent)
{
    switch (dwEvent)
    {
        case CTRL_C_EVENT:
        fprintf(stderr, "ctrl_c\n");
        return TRUE;
        default:
        return FALSE;
    }
}
}

    # Quick and dirty test CTRL_C interception in windows.
    critcl::cproc SetCtrlHandler {} ok {
        BOOL b = SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), ENABLE_PROCESSED_INPUT);
        if (b)
           b = SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE);
        return b ? TCL_OK : TCL_ERROR;
    }
}

使用critcl -lib ctrl_c.tcl编译。

然而!一旦看到Ctrl-C,控制台输入就不再回显用户键入的任何内容。它确实读取输入并对其进行操作但不回显该输入。作为示例会话:

% load ctrl_c.dll ctrl_c
% win32::SetCtrlHandler
% ctrl_c
8.6.1
% -blocking 1 -buffering line -buffersize 4096 -encoding unicode -eofchar → -translation auto
% -blocking 1 -buffering line -buffersize 4096 -encoding unicode -eofchar {} -translation crlf
%

未显示的是我输入fconfigure stdinfconfigure stdout的位置。希望这可以帮助您寻找解决方案。

答案 1 :(得分:2)

关于twapi :: set_console_control_handler,它要求事件循环运行才能生效。如果Tcl线程在100ms内没有响应,则处理Ctrl-C的线程将继续使用默认的OS提供的处理程序。如果没有收到响应,也许这应该更改为默认为不传递给OS处理程序。