GUI 应用程序中的 Tcl 通道

Posted

技术标签:

【中文标题】GUI 应用程序中的 Tcl 通道【英文标题】:Tcl Channel in GUI Application 【发布时间】:2013-08-28 21:51:16 【问题描述】:

我正在尝试将 Tcl 解释器嵌入到 C# GUI 应用程序中,并且一切正常, 甚至 AttachingNewFunction 到 TclCommand。 但有一件事对我来说很难, 我想重定向 标准输出、标准输入、标准错误 到一些TextBox'es。 我现在使用 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'es,但它很容易。

【问题讨论】:

我建议先在 Tcl 中实现通道。甚至还有示例代码。 (如果您不介意使用 Tk 的文本小部件,请尝试 tcl::chan::textwindow) 您可能希望将通道类型声明设为static struct; Tcl 假定它是。 (它就像一个 vtable,除了一个 C API。) static 旁边的 typePtr 没有帮助。我像这样创建 typePtr *static Tcl_ChannelType typePtr = new Tcl_ChannelType(); 【参考方案1】:

低级别 Tcl 通道的文档并不是最简单的,因此查看示例代码可能很有启发性。 Tk 实现中的generic/tkConsole.c 显示了真正的标准输出和标准错误重定向是如何完成的。特别是,需要非 NULL 值的字段是 nameversioncloseProc(或 close2Proc)、inputProcoutputProcwatchProcgetHandleProc,以及许多对于您创建的用于处理 stdout 和 stderr 的通道,这些实际上可能是假的。

但是,Tk 控制台小部件实际上并不支持提供真正的标准输入(相反,它使用Tcl_Eval 在主解释器中运行命令)并且它提供的只是声称始终位于文件末尾.这有点逃避现实。此外,没有一个通道根本能够传递给子进程,因为它们在操作系统级别没有任何表示。解决这个问题需要大量的工作(可能使用匿名管道和工作线程以及处理不可避免的缓冲问题的技巧;使用像 Expect 包这样的东西会做得更完整,尽管代价是 甚至更多 复杂性)。

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

【讨论】:

当我运行程序时,没有我实现的功能正在崩溃。

以上是关于GUI 应用程序中的 Tcl 通道的主要内容,如果未能解决你的问题,请参考以下文章

Python应用tkinter简介

Python应用tkinter简介

TCL/TK是啥?

在与其他源 tcl 文件相同的目录中创建 tcl 包的问题

Tcl/Tk教程_编程入门自学教程_菜鸟教程-免费教程分享

TCL:Windows中线程之间的双向通信