0

我试图将 Tcl 解释器嵌入到 C# GUI 应用程序中,并且一切正常,甚至 AttachingNewFunction 到 TclCommand。但有一件事对我来说很难,我想将 stdout、stdin、stderr 重定向到一些 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 进行调试,但我不相信他。当我编译&运行什么都没有发生时,标准输出不起作用,结果是例如

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,但它很容易。

4

1 回答 1

1

低级别 Tcl 通道的文档并不是最简单的,因此查看示例代码可能很有指导意义。generic/tkConsole.c在 Tk 的实现中显示了真正的 stdout 和 stderr 重定向是如何完成的。特别是,需要非 NULL 值的字段是nameversioncloseProc(或close2Proc)、、inputProc和,其中许多实际上可以是您创建的用于处理 stdout 和 stderr 的通道的虚拟对象。outputProcwatchProcgetHandleProc

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

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

于 2013-08-27T08:17:44.343 回答