[IronPython] Hosting: Delegates from Ironpython to C#
Tim Riley
riltim at gmail.com
Thu Aug 30 17:59:01 CEST 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 Ironpython-users
mailing list