2016-12-21 5 views
0

Я пытаюсь создать графический интерфейс WPF для управления интерфейсом IXIA, который написан в TCL (IXIA - приложение, которое управляет оборудованием), версия TCL - 86.
Для этого я создал следующее:Получение «невозможно найти канал с именем« stdout »error» при использовании C# WPF

  1. C# проект, который состоит из
    1. класса TCL_API.cs - содержит TCL библиотеки DLL.
    2. IXIA.cs class - содержит все методы доступа к IXIA additianlly метод evalScript, который вызывает класс TCL_API.cs, который является дескриптором команд TCL.
  2. WPF в visual Studio 2013. С вызовами методов для IXIA.cs.

Проблема заключается в том, что одна из команд TCL получить ошибку «не может найти канал под названием„стандартный вывод“. Как выяснилось, его, вероятно, происходит потому, что эта команда TCL содержит puts метод внутри. Я думаю, puts переопределения может решить эту проблему, но дон «знает, как сделать это, как я не» т есть весь код TCL, но только библиотеки DLL

Смотрите код:.

  1. T clAPI.cs

    class TclAPI 
    { 
        [DllImport("tcl86.DLL", CallingConvention = CallingConvention.Cdecl)] 
        public static extern int Tcl_Init(IntPtr interp); 
        [DllImport("tcl86.DLL", CallingConvention = CallingConvention.Cdecl)] 
        public static extern IntPtr Tcl_CreateInterp(); 
        [DllImport("tcl86.Dll", CallingConvention = CallingConvention.Cdecl)] 
        public static extern int Tcl_Eval(IntPtr interp, string skript); 
        [DllImport("tcl86.Dll", CallingConvention = CallingConvention.Cdecl)] 
        public static extern IntPtr Tcl_GetObjResult(IntPtr interp); 
        [DllImport("tcl86.Dll", CallingConvention = CallingConvention.Cdecl)] 
        unsafe public static extern char* Tcl_GetStringFromObj(IntPtr tclObj, IntPtr length); 
    } 
    
  2. IXIA.cs конструктор:

    public IXIA(string ip, string username="admin", string password = "admin") 
    { 
        interp = TclAPI.Tcl_CreateInterp(); 
        TclAPI.Tcl_Init(interp); 
        if (interp == IntPtr.Zero) 
        { 
         throw new SystemException("can not ini tialize Tcl interpreter"); 
        } 
        _ip = ip; 
        _userName = username; 
        _password = password; 
    } 
    
  3. метод evalScript в классе IXIA.cs:

    public int evalScript(string script) 
        { 
         int Evalres = TclAPI.Tcl_Eval(interp, script); 
         return Evalres; 
        } 
    

ответ

1

Поскольку вы взаимодействия с реальным Tcl, проблема в том, что стандартные каналы (из которых stdout являются участниками) не регистрируются. Я не совсем уверен, что не так, но проблема либо, что Tcl не полностью инициализирован, либо что вы создали свое общее приложение в режиме, который не поддерживает стандартные каналы.

Если это первое, добавив регистрацию Tcl_FindExecutable (принимает один char*, который может быть NULL, и возвращает void) и назвав его один раз, перед тем любые другие функции API Tcl будет исправить. (Эта функция немного неправильно названа;. Это на самом деле следовало бы назвать что-то вроде Tcl_InitLibrary или что-то подобное)

[DllImport("tcl86.DLL", CallingConvention = CallingConvention.Cdecl)] 
public static extern void Tcl_FindExecutable(string argv0); 
TclAPI.Tcl_FindExecutable(null); 

(см How can I run a static initializer method in C# before the Main() method? хороший способ, чтобы сделать этот вызов произойдет ровно один раз , это как раз тот код, который принадлежит статическому конструктору.)

Если последнее, вам нужно либо создать приложение в режиме, обеспечивающем доступность консоли, либо использовать Tcl_SetStdChannel для установки замены.Это общедоступный API, но ни один из них не предназначен для простого вызова с любых языков, отличных от C (или C++ в крайнем случае), поскольку он включает создание общего экземпляра канала Tcl сначала через Tcl_CreateChannel, и это нетривиальный API; Я думаю, вы, вероятно, должны считать это офф-лимитом, поскольку для того, чтобы хорошо использовать, для этого требуется довольно много знаний о канальной модели Tcl.

Из-за сложности API, я не буду вести вас через новый канал.


Вы могли попробовать заменить команду puts перед запуском сценария проблемы ... но как это используется для всех файлов и сокетов письменной форме, а не просто писать в консоль, вам нужно быть осторожным. Попробуйте оценить сценарий ниже перед запуском сценария проблемы:

rename puts puts_original 
proc puts {args} { 
    if {[llength $args] == 1} { 
     set args [linsert $args 0 stdout] 
    } elseif {[llength $args] == 2 && [lindex $args 0] eq "-nonewline"} { 
     set args [linsert $args 1 stdout] 
    } 
    if {[lindex $args end-1] eq "stdout"} { 
     # Doing nothing here, but might want to log somehow? 
    } else { 
     puts_original {*}$args 
    } 
} 

Это не код, который я рекомендовал бы нормально - это гораздо лучше, чтобы фактически исправить стандартные каналы так, чтобы они работали, и все это довольно слоеное - но иногда это лучшее, что можно сделать. Если код также не создает суб-интерпретаторы или потоки, в этом случае вы действительно застряли.

+0

Спасибо за ответ, я применил ваше прежнее решение. Он работал, но только тогда, когда я запускаю его в режиме отладки (щелчок выполняется изнутри VisualStudio), но при двойном щелчке по самому приложению (файл .exe) он возвращает ту же ошибку. Почему это так? Можно ли это исправить? –

 Смежные вопросы

  • Нет связанных вопросов^_^