Я пытаюсь встроить интерпретатор Tcl в приложение C # GUI, и все работает нормально,
даже прикрепление новой функции к 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 не самое простое, поэтому, возможно, полезно взглянуть на пример кода. generic/tkConsole.c
в реализации Tk показано, как выполняются реальные перенаправления stdout и stderr. В частности, поля, которые нуждаются в ненулевых значениях, являются name
, version
, closeProc
(или же close2Proc
), inputProc
, outputProc
, watchProc
а также getHandleProc
и многие из них могут быть фиктивными для каналов, которые вы создаете для обработки stdout и stderr.
Тем не менее, консольный виджет Tk не поддерживает создание реального стандартного ввода (вместо этого он использует Tcl_Eval
запускать команды в главном интерпретаторе) и тот, который он предоставляет, просто утверждает, что всегда находится в конце файла. Это немного отговорка. Кроме того, ни один из каналов не совсем может передаваться подпроцессам, поскольку они не имеют представления на уровне ОС. Исправление этого потребовало бы значительно больше работы (возможно, с помощью анонимных каналов и рабочих потоков и трюков, чтобы справиться с неизбежными проблемами буферизации; использование чего-то вроде пакета Expect сделало бы гораздо более полную работу, хотя и стоило бы даже больше сложности).
Вы, вероятно, хотите вернуть результаты, не связанные с ошибками. Например, всегда возвращаясь 0
от твоего outputProc
вызовет большие проблемы с общими частями канального кода Tcl; это предполагает, что это означает, что вещи заблокированы, и просто буферизует вещи до тех пор, пока не будет сказано, что они разблокированы. Для настоящей попытки проглотить все сначала верните количество записанных байтов, равное количеству байтов, которое вам было предложено записать. Точно так же важно сделать closeProc
работать правильно; если у вас нет данных экземпляра для удаления или ресурсов ОС, от которых можно избавиться, вы можете просто вернуть 0
там указывать что все ок.
Других решений пока нет …