GUI应用程序中的Tcl通道

本文关键字:Tcl 通道 应用程序 GUI | 更新日期: 2023-09-27 18:29:05

我正在尝试将Tcl解释器嵌入到C#GUI应用程序中,一切都很好,甚至将NewFunction附加到TclCommand。但有一件事对我来说很难,我想重定向stdout、stdin、stderr到一些TextBox。我现在使用C++,因为它更容易调试和编译。所以我使用代码

Tcl_Channel StdOut = Tcl_GetStdChannel(TCL_STDOUT);
Tcl_UnregisterChannel(interp,StdOut);
Tcl_Channel myStdOut = Tcl_CreateChannel(typePtr, "stdout",
    NULL, TCL_READABLE | TCL_WRITABLE);

Tcl_RegisterChannel(interp, myStdOut);
Tcl_SetStdChannel(myStdOut, TCL_STDOUT);

为了注册新的stdout,typePtr看起来像

typePtr->typeName = "stdout";
typePtr->version = TCL_CHANNEL_VERSION_2;
typePtr->getHandleProc = Tcl_MyDriverGetHandleProc;
typePtr->inputProc = Tcl_MyDriverInputProc;
typePtr->outputProc = Tcl_MyDriverOutputProc;
typePtr->flushProc = Tcl_MyDriverFlushProc;
typePtr->watchProc = Tcl_MyDriverWatchProc;
typePtr->closeProc = Tcl_MyDriverCloseProc;
typePtr->blockModeProc = Tcl_MyDriverBlockModeProc;
typePtr->seekProc = NULL;
typePtr->close2Proc = NULL;
typePtr->handlerProc = NULL;
typePtr->wideSeekProc = NULL;
typePtr->truncateProc = NULL;
typePtr->setOptionProc = NULL;
typePtr->getOptionProc = NULL;
typePtr->threadActionProc = NULL;

我连接的每个函数都返回TCL_OK或EINVAL(我从API知道)并将一些文本放入文件中,例如

int Tcl_MyDriverCloseProc(ClientData instanceData,
    Tcl_Interp *interp) {
    std::cout << "'n Tcl_MyDriverCloseProc'n";
    file << "'n Tcl_MyDriverCloseProc'n";
    file.flush();
    return EINVAL;
}

我也使用std::cout进行调试,但我不相信他。当我编译&什么都不运行,stdout不工作,结果是例如

result:stderr file8adcd0 stdout stdin:
result::

我编译的代码是

Tcl_GetChannelNames(interp);
std::cout << "result:" << Tcl_GetStringResult(interp) << ":'n";
Tcl_Eval(interp, "puts SomeOneHelp");
std::cout << "result:" << Tcl_GetStringResult(interp) << ":'n";

我也不能创建自定义通道并像一样使用它

"puts myChannel pleHdeeNI"

当我完成C++时,我将在C#中生成函数,将3个TCL标准通道写入TextBox,但这很容易。

GUI应用程序中的Tcl通道

低级别Tcl通道的文档不是最容易的,因此查看示例代码可能很有指导意义。Tk实现中的generic/tkConsole.c显示了如何进行真正的stdout和stderr重定向。特别是,需要非NULL值的字段是nameversioncloseProc(或close2Proc)、inputProcoutputProcwatchProcgetHandleProc,其中许多字段实际上可以是为处理stdout和stderr而创建的通道的伪值。

然而,Tk控制台小部件并不支持实际提供真正的stdin(相反,它使用Tcl_Eval在主解释器中运行命令),它提供的小部件只是声称总是在文件末尾。这有点逃避现实。此外,没有一个通道能够传递到子流程,因为它们在操作系统级别没有任何表示。解决这一问题需要做更多的工作(也许需要匿名管道和工作线程,以及处理不可避免的缓冲问题的技巧;使用Expect包这样的软件包会做得更完整,尽管代价是甚至更复杂)。

您可能希望从事物中返回无错误的结果。例如,总是从outputProc返回0会导致Tcl通道代码的通用部分出现很大问题;它假设这意味着事物被阻塞,只是缓冲事物,直到它被告知它们已经被阻塞。对于真正的"吞下一切"第一次尝试,返回所写的字节数与要求写入的字节数相同。同样,使closeProc正常工作也很重要;如果您没有要处理的实例数据或要处理的底层操作系统资源,您只需在那里返回0即可指示一切正常。