Version 43 of Tcl Interpreter in C# Application

Updated 2013-04-24 03:18:55 by APN

Here a short example how to use Tcl Interpreter and Tcl Scripting engine in C# .NET application. Warning here the first try to do it and it is simpler that one can suppose. In this example you use Tcl as so called unmanaged code form original tcl dll.


using System.Runtime.InteropServices;
using System;

namespace TclWrap {
    public class TclAPI {
         [DllImport("tcl84.DLL")]
         public static extern IntPtr Tcl_CreateInterp();
         [DllImport("tcl84.Dll")]
         public static extern int Tcl_Eval(IntPtr interp,string skript);
         [DllImport("tcl84.Dll")]
         public static extern IntPtr Tcl_GetObjResult(IntPtr interp);
         [DllImport("tcl84.Dll")]
         unsafe public static extern char* Tcl_GetStringFromObj(IntPtr tclObj,IntPtr length);
    }
    public class TclInterpreter {
        private IntPtr interp;
        public TclInterpreter() {
            interp = TclAPI.Tcl_CreateInterp();
            if (interp == IntPtr.Zero) {
                throw new SystemException("can not initialize Tcl interpreter");
            }
        }
        public int evalScript(string script) {
            return TclAPI.Tcl_Eval(interp,script);        
        }
        unsafe public string Result {
            get { 
                IntPtr obj = TclAPI.Tcl_GetObjResult(interp);
                if (obj == IntPtr.Zero) {
                    return "";
                } else {
                    return Marshal.PtrToStringAnsi((IntPtr)TclAPI.Tcl_GetStringFromObj(obj,IntPtr.Zero));
                }
            }
        }
    }
}

Using of it in C#

TclInterpreter interp = new TclInterpreter();
string result;
if (interp.evalScript("set a 3; {exp $a + 2}") != 0) {
    result = interp.Result;
}

You need to copy your tcl84.dll in application dictionary or in system dll dictionary. No futher requirements.

To have really useful tcl interpreter we need to define tcl proc that can invoke C# callback (delegates) and some infrastructure to get parameters from tcl calls. C# have also very good relextion (introspection) capatiblities. So it is possible to invoke all methods in assembly without to program special wrappers for all calls.

sample from Artur Trzewik

bigger sample tcl project (with gui interaction) with .NET executables

  • Callbacks to .NET (tcl proc ivoke .NET delegate)
  • Manipulatin of .NET object from Tcl with introspection (reflection) seting and reading of properties and instance variables

http://www.xdobry.de/tclinterop.zip

Warnig: Development state not productivity mature


Mono developer and all around guru Paolo Molaro says that the above works fine in Mono with the following addition to the mono config file:

<dllmap dll="tcl84.Dll" target="libtcl8.4.so.0" />

- davidw


TickleSharp: http://forge.novell.com/modules/xfmod/project/?ticklesharp

06.11.2003 I can not download this file.

10.11.2003 TickleSharp archive should be downloadable now.


05.02.2007 Artur's work helped me immensely in getting started with my own Tcl/.NET(C#) integration project, particularly the .zip file he references. However, I found that with newer tcl84.dll's (Artur included a .dll from May 2003 which worked fine), I got an access violation when I returned from delegate/callbacks. I will readily acknowledge an almost cargo-cult level of understanding of what exactly is happening here, but I've found that specifying the calling convention on the delegates seems to solve my issue with more recent Tcl builds:

[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
public unsafe delegate int Tcl_ObjCmdProc(IntPtr clientData,
                                          IntPtr interp,
                                          Int32 argc,
                                          byte** argv);

[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
public delegate void Tcl_DelCmdProc(IntPtr clientData);

[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
public unsafe delegate int Tcl_AppInitProc(IntPtr interp);

-nathan

This is an artifact of the compilation process used for the specific .dll build. The person performing the build should consider and document its choice of calling convention since this is easy to get wrong, and can lead to subtle errors regarding interop with mixed unix/win32/.net projects.


Eric - 2010-01-20 12:20:36

<interp.evalScript("cd c:/tcl/lib") invokes an AccessViolationException>


dkf - 2010-01-20 16:00:16

See also Eagle.


JJM - 2010-04-07

Specifically, please refer to the TclWrapper, TclApi, and TclBridge classes in Eagle.


Hi , I am trying to run "package require Expect" using this interpreter. But its showing Can't find package Expect. I am using Tcl 8.6 and I am able to use Expect package from command line. Could you Please suggest me some solution for this problem ? Also I called Tcl_Init() while creating this interpreter but still it doesnt work.

-Abhinav Parashar

isd - 2010-05-12

You could try loading the library directly with load /usr/lib/libexpect.so or load C:/Tcl/lib/expect/expect432.dll. That threw my tclsh into an infinite loop (threading issues?). The good news: my tiny "C# calling Expect" example ran fine with expect in pure Tcl. The latter has a slightly different API and fewer features than regular Expect, but it may be a close enough match for your needs.


DT - 2010-07-07 04:50:29

If I have my own application (written in C#) which implements internal commands, and I want to integrate Tcl capabilities into it, what is the best way ?

What I do now is creating my own console window, and use Tcl interpreter as given in the sample above. I also use unknown command to catch all other commands and then attempt to call internal commands. The only obstacle I have is how to use Tk. Which of these methods are correct ?

package require Tk

OR

load tk85.dll


sergio - 2012-01-12

I get error "can't find package SomePackage" when I call interp.evalScript("package require SomePackage")

How I can overcome this problem? The same command works fine in tclsh.


Jannis - 2012-06-11 11:31:29

I'm using this code with tcl85.dll and Visual Studio 2010 (.Net 4.0). When I tried it, I got PInvoke-Exceptions telling me that the stack got imbalanced. Changing the DllImport lines to

[DllImport("tcl85.dll", CallingConvention = CallingConvention.Cdecl)]

fixed it :) Thanks for the nice classes


RobinHsu - 2012-10-12 12:46:34

<Fixed some bugs in the C# codes above.>


Carl - 2013-04-23 23:33:33

With visual studio 2012, the example returns result == "invalid command name \"exp $a + 2\" Any suggestions?