0

Tcl インタープリターを C# GUI アプリケーションに埋め込もうとしていますが、NewFunction を TclCommand にアタッチしても、すべて正常に動作します。しかし、私にとって難しいことの1つは、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 もデバッグに使用していますが、彼を信じていません。コンパイルして実行すると何も起こらず、標準出力が機能しません。結果はたとえば

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 に書き込みますが、簡単です。

4

1 に答える 1

1

低レベルの Tcl チャネルのドキュメントは簡単ではないため、サンプル コードを参照することをお勧めします。generic/tkConsole.cTk の実装では、実際の stdout と stderr のリダイレクトがどのように行われるかを示しています。特に、非 NULL 値を必要とするフィールドは、、、name(または) version、、、およびであり、これらの多くは実際には、stdout および stderr を処理するために作成するチャネルのダミーになる可能性があります。closeProcclose2ProcinputProcoutputProcwatchProcgetHandleProc

ただし、Tk コンソール ウィジェットは、実際の stdin の提供を実際にはサポートせず (代わりにTcl_Eval、メイン インタープリターでコマンドを実行するために使用します)、それが提供するものは、常にファイルの終わりにあると主張するだけです。それはちょっとした警官です。また、 OS レベルでの表現がないため、サブプロセスに渡すことができるチャネルはまったくありません。これを修正するには、非常に多くの作業が必要になります (おそらく、匿名パイプとワーカー スレッド、および避けられないバッファリングの問題に対処するためのトリックが必要です。Expect パッケージのようなものを使用すると、さらに複雑になりますが、はるかに完全な作業を行うことができます)。

おそらく、物事からエラー以外の結果を返したいと思うでしょう。たとえば、0あなたのoutputProcwill から常に戻ると、Tcl のチャネル コードの一般的な部分で大きな問題が発生します。これは、物事がブロックされていることを意味すると想定し、ブロックが解除されたことが通知されるまで、単にバッファーに入れます。すべてを飲み込む最初の試行では、書き込みを要求されたバイト数と同じバイト数を返します。closeProc同様に、仕事を正しくすることも重要です。破棄するインスタンス データや、削除する基盤となる OS リソースがない場合は、0そこに戻って、すべて問題がないことを示すことができます。

于 2013-08-27T08:17:44.343 に答える