我试图将Tcl解释器嵌入到C#GUI应用程序中,并且一切正常,
甚至将NewFunction附加到TclCommand。
但是有一件事对我来说很难
我想重定向
标准输出,标准输入,标准错误
一些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);


注册新的标准输出,
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,但是很容易。

最佳答案

Tcl通道级别低的文档并不是最简单的,因此查看示例代码可能很有帮助。 Tk的实现中的generic/tkConsole.c显示了实际的stdout和stderr重定向是如何完成的。特别是,需要非空值的字段为nameversioncloseProc(或close2Proc),inputProcoutputProcwatchProcgetHandleProc,其中许多对于您创建的用于处理stdout和stderr的通道,这些实际上可能是虚拟的。

但是,Tk控制台窗口小部件实际上不支持提供实际的stdin(相反,它使用Tcl_Eval在主解释器中运行命令),而它提供的窗口仅声明始终位于文件末尾。这有点无济于事。同样,所有通道都无法传递给子流程,因为它们在操作系统级别上没有任何表示形式。要解决此问题,将需要进行大量工作(也许使用匿名管道和工作线程以及一些技巧来处理不可避免的缓冲问题;使用Expect程序包之类的工具会做得多得多的工作,尽管代价是更加复杂)。

您可能想返回事物的非错误结果。例如,始终从0返回outputProc会导致Tcl通道代码的通用部分出现严重问题。它假定这意味着事物已被阻塞,只是缓冲事物直到被告知它们已变得不受阻塞为止。对于真正的吞咽一切,请返回与要求写入的字节数相同的字节数。同样,正确使用closeProc也很重要;如果您没有要处理的实例数据或要摆脱的基础OS资源,则可以在其中返回0表示一切正常。

07-24 09:46
查看更多