Windows控制台中的Tcl和Ctrl-C

Windows控制台中的Tcl和Ctrl-C,windows,tcl,interrupt,windows-console,Windows,Tcl,Interrupt,Windows Console,我在Windows Tcl 8.5应用程序中拦截Ctrl-C时遇到问题。我在开发的扩展库中添加了一个控制台处理程序,但它并不总是有效的 如果某个Tcl代码正在执行,那么一切都正常。但是,如果应用程序正在等待用户输入,则按Ctrl-C将终止它。我的处理程序被调用,但同时(在不同的线程中?)Tcl REPL调用Tcl\u Exit。这真的把一切都搞砸了 据我所知,调用REPL callsTcl\u Exit是因为它错误地认为stdin遇到了EOF。这又是由于按下Ctrl-C时,读取例程返回,并返回读

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

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

据我所知,调用REPL calls
Tcl\u Exit
是因为它错误地认为
stdin
遇到了
EOF
。这又是由于按下Ctrl-C时,读取例程返回,并返回读取的字节数,即零。REPL将此条件解释为EOF

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


我试过
twapi::set\u console\u control\u handler
,但似乎根本不起作用。按下Ctrl-C总是终止应用程序,并且永远不会调用处理程序。

的MSDN文档指出,Ctrl\U C处理是单独处理的,但可以通过将控制台模式设置为
启用处理的\u输入来禁用。然后将Ctrl-C事件报告为键盘输入

以下critcl代码加载到解释器中(使用
load ctrl\u c.dll ctrl\u 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;
    }
}

未显示的是我输入的
fconfigure stdin
fconfigure stdout
的位置。希望这能帮助您搜索解决方案。

的MSDN文档指出,CTRL\u C处理是单独处理的,但可以通过将控制台模式设置为
启用处理的\u输入来禁用。这是n将Ctrl-C事件报告为键盘输入

以下critcl代码加载到解释器中(使用
load ctrl\u c.dll ctrl\u 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;
    }
}

没有显示的是我输入的
fconfigure stdin
fconfigure stdout
的位置。希望这可以帮助您搜索解决方案。

关于twapi::set_console_control_handler,它需要运行事件循环才能有效。处理Ctrl-C的线程将继续使用默认操作系统提供的handler如果Tcl线程在100ms内没有响应。如果没有收到响应,可能应该将其更改为默认值,即不传递给操作系统处理程序。

关于twapi::set_console_control_处理程序,它要求事件循环运行才能生效。处理Ctrl-C的线程将继续使用默认操作系统提供的处理程序如果Tcl线程在100毫秒内没有响应。如果没有收到响应,可能应该将其更改为默认值,不传递给操作系统处理程序。

我尝试了一个快速的critcl内置扩展来调用SetConsoletrlHandler并获得相同的效果。处理程序函数被调用,但tclsh仍然存在。我怀疑它引发的twapi版本运行脚本的事件在处理该事件之前退出,因此无法调用脚本。可能正在调用C处理程序。我尝试了一个快速的critcl内置扩展来调用SetConsoleTlHandler并获得相同的效果。虽然调用了处理程序函数,但tclsh仍然退出。我怀疑在twapi版本中,它会引发一个事件以运行e脚本并在事件处理之前退出,因此无法调用脚本。C处理程序可能正在被调用。设置
ENABLE\u processed\u INPUT
类似于在Unix终端上设置raw/noecho模式。使用计时器事件在几微秒内重置它是否足够?我真的不知道…它看起来像setting
ENABLE_PROCESSED_INPUT
就像在Unix终端上设置raw/noecho模式。使用计时器事件在几微秒内重置它是否足够?我真的不知道……添加了一个RFE来更改Tcl更新的Tcl主干(8.6.4之后)不要把Ctrl-C当作控制台上的EOF。非常感谢。我刚刚下载了最新版本,Ctrl-C不会立即终止我的程序。添加了一个RFE来更改Tcl更新的Tcl主干(8.6.4之后)不要把Ctrl-C当作控制台上的EOF。非常感谢。我刚刚下载了最新版本,Ctrl-C不会立即终止我的程序。