Пример #1
0
        ///////////////////////////////////////////////////////////////////////////////////////////////
        //
        // -- CmdDeleteProc --
        //
        // DeleteProc will be invoked when (if) name is deleted. This can occur through a
        // call to Tcl_DeleteCommand, Tcl_DeleteCommandFromToken, or Tcl_DeleteInterp, or
        // by replacing name in another call to Tcl_CreateObjCommand. DeleteProc is
        // invoked before the command is deleted, and gives the application an
        // opportunity to release any structures associated with the command.
        //
        private static void CmdDeleteProc(
            IntPtr clientData
            )
        {
            //
            // NOTE: We need to kill the associated TclBridge object
            //       instance and remove any references to the bridge
            //       from the containing interpreter.
            //
            try
            {
                //
                // NOTE: Rehydrate the handle from the clientData that Tcl just
                //       passed us.
                //
                GCHandle handle = GCHandle.FromIntPtr(clientData); /* throw */

                //
                // NOTE: Make sure the handle has a valid target.
                //
                if (handle.IsAllocated && (handle.Target != null))
                {
                    //
                    // NOTE: Attempt to cast the handle to a TclBridge object; if this
                    //       fails, we cannot continue to handle this call.
                    //
                    TclBridge tclBridge = handle.Target as TclBridge;

                    if (tclBridge != null)
                    {
                        //
                        // NOTE: Skip messing with the TclBridge or interpreter object if it is
                        //       already being disposed (i.e. we are NOT being called directly
                        //       due to the command being removed from the Tcl interpreter or
                        //       the Tcl interpreter being deleted). The caller of the dispose
                        //       method will handle removing the TclBridge object from the
                        //       collection in the interpreter.
                        //
                        if (!tclBridge.disposing)
                        {
                            //
                            // NOTE: Grab the associated interpreter from the TclBridge
                            //       object.
                            //
                            Interpreter interpreter = tclBridge.interpreter;

                            //
                            // NOTE: Remove all instances of the TclBridge object from its
                            //       interpreter.
                            //
                            if (interpreter != null)
                            {
                                /* IGNORED */
                                interpreter.RemoveTclBridges(tclBridge);
                            }

                            //
                            // NOTE: Prevent the Dispose method from trying to delete the Tcl
                            //       command itself (since it is already being deleted).
                            //
                            tclBridge.token = IntPtr.Zero;

                            //
                            // NOTE: Cleanup all the resources used by this TclBridge object.
                            //       In theory, this object disposal can throw; however, in
                            //       practice we know that it does not attempt to do anything
                            //       that can actually "fail" unless it has a valid command
                            //       token, which we have already cleared (Tcl has notified us,
                            //       by calling this delegate, that it has already deleted the
                            //       command in question).
                            //
                            tclBridge.Dispose(); /* throw */
                        }
                    }
                    else
                    {
                        TraceOps.DebugTrace(
                            "invalid Tcl bridge object",
                            typeof(Tcl_CmdDeleteProc).Name,
                            TracePriority.MarshalError);
                    }
                }
                else
                {
                    TraceOps.DebugTrace(
                        "invalid GC handle",
                        typeof(Tcl_CmdDeleteProc).Name,
                        TracePriority.MarshalError);
                }
            }
            catch (Exception e)
            {
                //
                // NOTE: Nothing we can do here except log the failure.
                //
                TraceOps.DebugTrace(
                    e, typeof(Tcl_CmdDeleteProc).Name,
                    TracePriority.NativeError);
            }
        }
Пример #2
0
        ///////////////////////////////////////////////////////////////////////////////////////////////

        #region Static "Factory" Members
        public static TclBridge Create(
            Interpreter interpreter,
            IExecute execute,
            IClientData clientData,
            IntPtr interp,
            string name,
            bool fromThread,
            bool forceDelete,
            bool noComplain,
            ref Result error
            )
        {
            //
            // NOTE: Create and return a TclBridge object that creates and
            //       associates a named Tcl command with the specified Eagle
            //       command.
            //
            //       The marshalling of the command arguments and the result
            //       will be handled by this class (via the ObjCmdProc wrapper).
            //
            //       Tcl command lifetime management will also be handled by
            //       this class (via the CmdDeleteProc).
            //
            //       Eagle command lifetime management will also be handled by
            //       this class.  The Tcl command will be deleted if the Eagle
            //       command is deleted.
            //
            if (interpreter != null)
            {
                ITclApi tclApi = TclApi.GetTclApi(interpreter);

                if (TclApi.CheckModule(tclApi, ref error))
                {
                    if (tclApi.CheckInterp(interp, ref error))
                    {
                        if (execute != null)
                        {
                            //
                            // NOTE: *WARNING* Empty Tcl command/procedure names are allowed,
                            //       please do not change this to "!String.IsNullOrEmpty".
                            //
                            if (name != null)
                            {
                                //
                                // NOTE: Create a TclBridge object to handle the command
                                //       callbacks from Tcl.
                                //
                                ReturnCode code   = ReturnCode.Ok;
                                TclBridge  result = null;

                                try
                                {
                                    result = new TclBridge(
                                        interpreter,
                                        execute,
                                        clientData,
                                        interp,
                                        new Tcl_ObjCmdProc(ObjCmdProc),
                                        new Tcl_CmdDeleteProc(CmdDeleteProc),
                                        IntPtr.Zero,
                                        fromThread,
                                        forceDelete,
                                        noComplain);

                                    //
                                    // NOTE: Create the Tcl command that calls into the ObjCmdProc
                                    //       callback TclBridge dispatcher methods and save the
                                    //       created Tcl command token for later deletion.
                                    //
                                    code = TclWrapper.CreateCommand(
                                        tclApi,
                                        interp,
                                        name,
                                        result.objCmdProc,
                                        GCHandle.ToIntPtr(result.handle),
                                        result.cmdDeleteProc,
                                        ref result.token,
                                        ref error);

                                    if (code == ReturnCode.Ok)
                                    {
                                        return(result);
                                    }
                                }
                                catch (Exception e)
                                {
                                    error = e;
                                    code  = ReturnCode.Error;
                                }
                                finally
                                {
                                    if ((code != ReturnCode.Ok) &&
                                        (result != null))
                                    {
                                        //
                                        // NOTE: Dispose and clear the partially created TclBridge
                                        //       object because the Tcl command creation failed.
                                        //       This can throw an exception if the command token
                                        //       is valid and we cannot manage to delete it; however,
                                        //       since Tcl command creation is the very last step
                                        //       above, this corner case should be rare.
                                        //
                                        result.Dispose(); /* throw */
                                        result = null;
                                    }
                                }
                            }
                            else
                            {
                                error = "invalid command name";
                            }
                        }
                        else
                        {
                            error = "invalid command target";
                        }
                    }
                }
            }
            else
            {
                error = "invalid interpreter";
            }

            return(null);
        }