public static unsafe void Helper_RegisterProc(IntPtr interp, string name, Tcl_ObjCmdProc proc)
        {
            Tcl_CreateObjCommand(
                interp: interp,
                cmdName: name,
                proc: Marshal.GetFunctionPointerForDelegate(proc),
                clientData: IntPtr.Zero,
                deleteProc: IntPtr.Zero
                );

            TCL.CommandsList.RegisterExtraCommand(name);
        }
Example #2
0
        ///////////////////////////////////////////////////////////////////////////////////////////////

        private /* protected virtual */ void Dispose(
            bool disposing
            ) /* throw */
        {
            TraceOps.DebugTrace(String.Format(
                                    "Dispose: called, disposing = {0}, disposed = {1}",
                                    disposing, disposed), typeof(TclBridge).Name,
                                TracePriority.CleanupDebug);

            if (!disposed)
            {
                if (!this.disposing)
                {
                    //
                    // NOTE: We are now disposing this object (prevent re-entrancy).
                    //
                    this.disposing = true;

                    //
                    // NOTE: This method should not normally throw; however, if it does
                    //       we do not want our disposing flag to be stuck set to true.
                    //
                    try
                    {
                        //if (disposing)
                        //{
                        //    ////////////////////////////////////
                        //    // dispose managed resources here...
                        //    ////////////////////////////////////
                        //}

                        //////////////////////////////////////
                        // release unmanaged resources here...
                        //////////////////////////////////////

                        //
                        // NOTE: If necessary (and possible), delete the Tcl command via the
                        //       token we saved earlier (when the Tcl command was created).
                        //
                        ReturnCode deleteCode  = ReturnCode.Ok;
                        Result     deleteError = null;

                        //
                        // NOTE: If we have a valid command token then we are still hooked to
                        //       Tcl via our inbound native delegates and we must unhook
                        //       successfully or throw to prevent our internal object state
                        //       from being made inconsistent.
                        //
                        if (token != IntPtr.Zero)
                        {
                            if (interpreter != null)
                            {
                                ITclApi tclApi = TclApi.GetTclApi(interpreter);

                                //
                                // BUGFIX: We want to force deletion of this bridged command
                                //         if the force flag was specified upon creation OR
                                //         if the command is not actively being used.
                                //
                                deleteCode = TclWrapper.DeleteCommandFromToken(
                                    tclApi, interp, forceDelete || (objCmdProcLevels == 0),
                                    ref token, ref deleteError);
                            }
                            else
                            {
                                deleteError = "invalid interpreter";
                                deleteCode  = ReturnCode.Error;
                            }
                        }

                        //
                        // NOTE: Did we succeed in deleting the command from Tcl, if it
                        //       was necessary?
                        //
                        if (!noComplain && (deleteCode != ReturnCode.Ok))
                        {
                            //
                            // NOTE: If the command deletion was necessary and it failed
                            //       for any reason, complain very loudly.
                            //
                            DebugOps.Complain(interpreter, deleteCode, deleteError);

                            //
                            // BUGFIX: Also, we must throw an exception here to prevent
                            //         the delegates from being disposed while Tcl still
                            //         refers to them (tclLoad-1.2 GC race).
                            //
                            throw new ScriptException(deleteCode, deleteError);
                        }

                        //
                        // NOTE: If necessary, release the GCHandle that is keeping this
                        //       object alive.
                        //
                        if (handle.IsAllocated)
                        {
                            handle.Free();
                        }

                        //
                        // NOTE: We do not own these objects; therefore, we just null out
                        //       the references to them (in case we are the only thing
                        //       keeping them alive).
                        //
                        interpreter = null;
                        execute     = null;
                        clientData  = null;

                        //
                        // NOTE: Zero out our Tcl interpreter.  We do not delete it because
                        //       we do not own it.
                        //
                        interp = IntPtr.Zero;

                        //
                        // NOTE: Zero out our created Tcl command token.  We should not need
                        //       to call Tcl to delete the actual command because by this time
                        //       it should already have been deleted.
                        //
                        token = IntPtr.Zero;

                        //
                        // NOTE: Finally, we should be able to safely remove our references
                        //       to the Tcl callback delegates at this point because we already
                        //       deleted the Tcl command related to them.
                        //
                        objCmdProc    = null;
                        cmdDeleteProc = null;

                        //
                        // NOTE: Zero out our command nesting level.
                        //
                        objCmdProcLevels = 0;

                        //
                        // NOTE: This object is now disposed.
                        //
                        disposed = true;
                    }
                    finally
                    {
                        //
                        // NOTE: We are no longer disposing this object.
                        //
                        this.disposing = false;
                    }
                }
            }
        }
Example #3
0
        ///////////////////////////////////////////////////////////////////////////////////////////////

        #region Private Constructors
        private TclBridge(
            Interpreter interpreter,
            IExecute execute,
            IClientData clientData,
            IntPtr interp,
            Tcl_ObjCmdProc objCmdProc,
            Tcl_CmdDeleteProc cmdDeleteProc,
            IntPtr token,
            bool fromThread,
            bool forceDelete,
            bool noComplain
            )
        {
            //
            // NOTE: Lock this object in memory until we are disposed.
            //
            handle = GCHandle.Alloc(this, GCHandleType.Normal); /* throw */

            //
            // NOTE: This will be used to keep track of the nesting levels for
            //       the number of calls active to our Tcl_ObjCmdProc callback.
            //
            objCmdProcLevels = 0;

            //
            // NOTE: Setup the information we need to make callbacks.
            //
            this.interpreter = interpreter;
            this.execute     = execute;
            this.clientData  = clientData;

            //
            // NOTE: We need the Tcl interpreter later on (during cleanup) as well.
            //
            this.interp = interp;

            //
            // NOTE: Hold on to these delegates to prevent exceptions from
            //       being thrown when they magically "go away".
            //
            this.objCmdProc    = objCmdProc;
            this.cmdDeleteProc = cmdDeleteProc;

            //
            // NOTE: Keep track of the created Tcl command token.
            //
            this.token = token;

            //
            // NOTE: Does this Tcl command belong to an isolated Tcl thread?
            //
            this.fromThread = fromThread;

            //
            // NOTE: Do they want to forcibly delete the Tcl command during dispose?
            //
            this.forceDelete = forceDelete;

            //
            // NOTE: Do they want to ignore errors from deleting the Tcl command
            //       during dispose?
            //
            this.noComplain = noComplain;
        }