[IronPython] Hosting: Delegates from Ironpython to C#

Tim Riley riltim at gmail.com
Thu Aug 30 08:59:01 PDT 2007


Dino:

I was trying something similar to what you had posted and was getting
an error. I also just tried the code you gave me with a minor
correction to fix the CommandFlags part and received the error below.
If it helps I have also added the C# code use to call the python file
below the error if that will help at all.


*********ERROR***********
Command: pyfile
System.AccessViolationException: Attempted to read or write protected memory.
This is often an indication that other memory is corrupt.
   at PyAcadDotNet.PyAcadCmd.RegPyCmd(String cmd_group, String cmd_name,
CommandFlags cmd_flags, CmdDelegate cmd_delegate)
   at PyAcadDotNet.PyAcadCmd.PythonRegister(String CommandName, CmdDelegate
FuncPointer, CommandFlags flags) in C:\Documents and Settings\TJRiley\My
Documents\pyacaddotnet\registercommand.cs:line 65
   at PythonRegister##20(Object , Object , Object )
   at IronPython.Runtime.Calls.CallTarget3.Invoke(Object arg0, Object arg1,
Object arg2)
   at IronPython.Runtime.Calls.FastCallable3.Call(ICallerContext context,
Object arg0, Object arg1, Object arg2)
   at IronPython.Runtime.Calls.BuiltinFunction.Call(ICallerContext context,
Object arg0, Object arg1, Object arg2)
   at IronPython.Runtime.Operations.Ops.CallWithContext(ICallerContext context,
Object func, Object arg0, Object arg1, Object arg2)
   at C:\Documents and Settings\TJRiley\My
Documents\pyacaddotnet\Samples\commandmethod_test.py##22(ModuleScope )
   at IronPython.Hosting.CompiledCodeDelegate.Invoke(ModuleScope moduleScope)
   at IronPython.Hosting.CompiledCode.Run(ModuleScope moduleScope)
   at IronPython.Hosting.CompiledCode.Execute(EngineModule engineModule,
IDictionary`2 locals)
   at IronPython.Hosting.CompiledCode.Execute()
   at PyAcadDotNet.AcadInterface.pythonfile() in C:\Documents and
Settings\TJRiley\My Documents\pyacaddotnet\PyAcadDotNet.cs:line 98
*********ERROR***********


*********CODE**************
using System;
using System.Collections;
using System.Windows.Forms;
using System.IO;
using System.Text;
using System.Runtime.InteropServices;

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;

using AcEd = Autodesk.AutoCAD.EditorInput;
using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application;

using IronPython.Hosting;

namespace PyAcadDotNet
{
  public class AcadInterface : IExtensionApplication
  {
    static internal AcEd.Editor ed =
AcadApp.DocumentManager.MdiActiveDocument.Editor;

    public delegate void TestDelegate();


    public void Initialize()
    {
      ed.WriteMessage("\nPyAcad.NET Loaded Successfully....");
      ed.WriteMessage("\ntype 'pyhelp' for commands....");
    }

    public void Terminate()
    {
      this.Terminate();
    }

    internal delegate void AddReference(object assembly);

    [CommandMethod("pyfile", CommandFlags.Session)]
    static public void pythonfile()
    {
      using (PythonEngine engine = new PythonEngine())
      {
        using (AcadCommandLine myCommandLine = new AcadCommandLine())
        {
          try
          {
            // Create a new instance of PythonEngine and set variables.
            engine.AddToPath(Environment.CurrentDirectory);
            // Send Stdout and Stderr to the AutoCAD command line.
            engine.SetStandardOutput(myCommandLine);
            engine.SetStandardError(myCommandLine);
            engine.Import("clr");
            PyAcadCmd regcmds = new PyAcadCmd();
            engine.Globals.Add("regcmds", regcmds);
            //lets load some AutoCAD assemblies.
            AddReference adr =
engine.CreateMethod<AddReference>("clr.AddReference(assembly)");
            adr(typeof(BlockTableRecord).Assembly);
            adr(typeof(Editor).Assembly);

            // Display an OpenFileDialog and run the script.
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "Python files (*.py)|*.py|All files (*.*)|*.*";
            ofd.ShowDialog();

            // Run the file selected by the open file dialog box.
            //engine.ExecuteFile(ofd.FileName);
            CompiledCode cc = engine.CompileFile(ofd.FileName);
            cc.Execute();
          }
          catch (System.Exception e)
          {
            ed.WriteMessage(e.ToString());
          }
        }
      }
    }
 }

  //
  public class AcadCommandLine : Stream
  //Modified version of a class coded by Mike Stall.
  {
    public AcadCommandLine()
    {
      //constructor
    }

    #region unsupported Read + Seek members
    public override bool CanRead
    {
      get { return false; }
    }

    public override bool CanSeek
    {
      get { return false; }
    }

    public override bool CanWrite
    {
      get { return true; }
    }

    public override void Flush()
    {
      //
    }

    public override long Length
    {
      get { throw new NotSupportedException("Seek not supported"); }
// can't seek
    }

    public override long Position
    {
      get
      {
        throw new NotSupportedException("Seek not supported");  // can't seek
      }
      set
      {
        throw new NotSupportedException("Seek not supported");  // can't seek
      }
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
      throw new NotSupportedException("Reed not supported"); // can't read
    }

    public override long Seek(long offset, SeekOrigin origin)
    {
      throw new NotSupportedException("Seek not supported"); // can't seek
    }

    public override void SetLength(long value)
    {
      throw new NotSupportedException("Seek not supported"); // can't seek
    }
    #endregion

    public override void Write(byte[] buffer, int offset, int count)
    {
      try
      {
        // Very bad hack: Ignore single newline char. This is because
we expect the newline is following
        // previous content and we already placed a newline on that.
        AcEd.Editor ed = AcadApp.DocumentManager.MdiActiveDocument.Editor;

        if (count == 1 && buffer[offset] == '\n')
          return;

        StringBuilder sb = new StringBuilder();
        while (count > 0)
        {
          char ch = (char)buffer[offset];
          if (ch == '\n')
          {
            ed.WriteMessage(sb.ToString() + "\n");
            sb.Length = 0; // reset.
          }
          else if (ch != '\r')
          {
            sb.Append(ch);
          }

          offset++;
          count--;
        }
        if (sb.Length > 0)
          ed.WriteMessage(sb.ToString() + "\n");
      }
      catch (System.Exception e)
      {
        throw e;
      }
    }
  }
}
*********CODE**************
On 8/30/07, Dino Viehland <dinov at exchange.microsoft.com> wrote:
> I think you should be able to just pass a function object to PythonRegister and it should be converted into a delegate.  For example:
>
> import clr
> clr.AddReference('PyAcadDotNet')
> from PyAcadDotNet import PyAcadCmd
>
> def foo():
>         print 'hello world'
>
> PyAcadCmd.PythonRegister('some command', foo, CommandFlags.Whatever)
>
> Does that not work?
>
> -----Original Message-----
> From: users-bounces at lists.ironpython.com [mailto:users-bounces at lists.ironpython.com] On Behalf Of Tim Riley
> Sent: Wednesday, August 29, 2007 7:10 PM
> To: Discussion of IronPython
> Subject: [IronPython] Hosting: Delegates from Ironpython to C#
>
> I'm embedding IronPython in a C# dll that is hosted inside a program
> called AutoCAD. In order to register commands in AutoCAD from .NET I
> need to P/Invoke a C function inside a .dll. I can do this fairly easy
> from C# but I can't figure out the right way to call my C# wrapper
> from IronPython to have it register the command. I have perused the
> hosting docs for 1.1 and haven't been able to come up with a solution
> that works. Here is my C# code. I either want to call the PyRegCmds
> void or the PythonRegister void.  Both of which expect a delegate.for
> example if I had a python function like:
>
> def test1:
>     print "This is a test".
>
> I can't figure out how to map test to the delegate required in the code below.
> Note: I can call this from C# fine. See :static public void test().
>
> Can anyone give me any pointers? It would be greatly appreciated.
>
>
> code:
>
> using System ;
> using System.Runtime.InteropServices;
> using Autodesk.AutoCAD.Runtime ;
> using Autodesk.AutoCAD.EditorInput;
>
> namespace PyAcadDotNet
> {
>         /// <summary>
>         /// PyAcadCmd Class:
>         /// Used to register commands on the AutoCAD command stack.
>         /// </summary>
>         public class PyAcadCmd
>         {
>                 public PyAcadCmd()
>                 {
>                 }
>                 public delegate void CmdDelegate();
>
>                 /// <summary>
>                 /// RegPyAcadCmd:
>                 /// Registers a delegate (callback) with the AutoCAD command string
>                 /// on the command stack.
>                 /// </summary>
>         [DllImport("PyRegCmd.dll",
>                          CallingConvention=CallingConvention.Cdecl,CharSet = CharSet.Unicode,
>                          EntryPoint = "?RegPyCmd@@YAXPB_W0HP6AXXZ at Z")]
>                 public static extern void RegPyCmd(
>                         string cmd_group,
>                         string cmd_name,
>                         Autodesk.AutoCAD.Runtime.CommandFlags cmd_flags,
>                         [MarshalAs(UnmanagedType.FunctionPtr)] PyAcadCmd.CmdDelegate cmd_delegate);
>
>
>         public static void PythonRegister(string CommandName,
> CmdDelegate FuncPointer, CommandFlags flags)
>         {
>             RegPyCmd("_pycmds", CommandName, flags, FuncPointer);
>         }
>
>         //testing stuff
>         public static void testcommand()
>         {
>             Editor ed =
> Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;
>             ed.WriteMessage("\ncb1 delegate seems to work!\n");
>         }
>         [CommandMethod("regcmds")]
>         static public void test() // This method can have any name
>         {
>             CmdDelegate cb1 = new CmdDelegate(PyAcadCmd.testcommand);
>             PythonRegister("testcommand", cb1, CommandFlags.Session);
>         }
>         }
>
>
> }
> _______________________________________________
> Users mailing list
> Users at lists.ironpython.com
> http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
> _______________________________________________
> Users mailing list
> Users at lists.ironpython.com
> http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
>


More information about the Users mailing list