Dino:
I tried using the PythonDelegateWrapper you posted below with the same
results. To make things easier I tried moving all my testing into a
single C# file and have it run the code from C# instead of a compiling
a python file. Below is the code. When I execute "regtest" in AutoCAD
it fatal errors on me. I also added
System.Environment.SetEnvironmentVariable("COMPlus_MDA", "1"); to the
initialize of my code but it doesn't do anything for me. Any other
ideas?
********code*********
using System ;
using System.Runtime.InteropServices;
using Autodesk.AutoCAD.Runtime ;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using IronPython.Hosting;
namespace PyAcadDotNet
{
/// <summary>
/// PyAcadCmd Class:
/// Used to register commands on the AutoCAD command stack.
/// </summary>
public class PyAcadCmd
{
public PyAcadCmd()
{
}
public delegate void CmdDelegate();
internal delegate void AddReference(object assembly);
/// <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@@[EMAIL PROTECTED]")]
public static extern void RegPyCmd(
string cmd_group,
string cmd_name,
Autodesk.AutoCAD.Runtime.CommandFlags cmd_flags,
[MarshalAs(UnmanagedType.FunctionPtr)] CmdDelegate
cmd_delegate);
public static void PythonRegister(string CommandName,
CmdDelegate FuncPointer, CommandFlags flags)
{
RegPyCmd("_pycmds", CommandName, flags, new
CmdDelegate(new PythonDelegateWrapper(FuncPointer).Invoke));
}
//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);
}
[CommandMethod("regtest", CommandFlags.Session)]
static public void regtest()
{
PythonEngine engine = new PythonEngine();
engine.Import("clr");
AddReference adr =
engine.CreateMethod<AddReference>("clr.AddReference(assembly)");
adr(typeof(BlockTableRecord).Assembly);
adr(typeof(Editor).Assembly);
CompiledCode cc = engine.Compile(
@"
import Autodesk.AutoCAD.Runtime
import clr
clr.AddReference('PyAcadDotNet')
from PyAcadDotNet import PyAcadCmd
def foo():
print 'hello world'
PyAcadCmd.PythonRegister('pythontester', foo,
Autodesk.AutoCAD.Runtime.CommandFlags.Session)");
cc.Execute();
}
}
class PythonDelegateWrapper
{
private PyAcadCmd.CmdDelegate cmdDelegate;
public PythonDelegateWrapper(PyAcadCmd.CmdDelegate dlg)
{
cmdDelegate = dlg;
}
public void Invoke()
{
cmdDelegate();
}
}
}
********code**********
On 8/30/07, Dino Viehland <[EMAIL PROTECTED]> wrote:
> Well at this point we've successfully created the delegate and passed it off
> to you so it's hard to tell what's going wrong here. Couple of suggestions
> on things to try and troubleshoot the issue:
> Instead of handing the delegate you get off to the P/Invoke call can
> you just turn around and invoke the delegate from C# code and successfully
> call back into the Python code?
> If that works can you do something like:
>
> class PythonDelegateWrapper {
> private CmdDelegate cmdDelegate;
> public PythonDelegateWrapper(CmdDelegate dlg) {
> cmdDelegate = dlg;
> }
>
> public void Invoke() {
> cmdDelegate();
> }
> }
>
> And then pass "new CmdDelegate(new PythonDelegateWrapper(dlg).Invoke)" to the
> P/Invoke function?
>
> The reason why I'm proposing this is maybe there's a strange interaction
> between dynamic methods (which the Python delegate will be) and the P/Invoke
> call - this might help isolate the issue.
>
> And the final thing that might be interesting to try would be to make sure
> you keep the reference to the delegate alive during the lifetime of the call.
> In theory this should be happening for you automatically - but if the
> unmanaged side is going to hold onto this delegate for longer than the
> duration of the call you'll need to do this anyway. Given that you're still
> in the call this shouldn't be an issue but you could set the environment
> variable COMPlus_MDA=1 to enable CLR Managed Debugging Assistants to see if
> you get any warnings about that firing. I don't really believe this could be
> happening but it would be consistent w/ the exception you're getting.
>
> Those are my 1st two guesses as to what could be going wrong, hopefully one
> of them will be helpful :).
>
> -----Original Message-----
> From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Tim Riley
> Sent: Thursday, August 30, 2007 8:59 AM
> To: Discussion of IronPython
> Subject: Re: [IronPython] Hosting: Delegates from Ironpython to C#
>
> 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 <[EMAIL PROTECTED]> 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: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] 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@@[EMAIL PROTECTED]")]
> > 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
> > [email protected]
> > http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
> > _______________________________________________
> > Users mailing list
> > [email protected]
> > http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
> >
> _______________________________________________
> Users mailing list
> [email protected]
> http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
> _______________________________________________
> Users mailing list
> [email protected]
> http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
>
_______________________________________________
Users mailing list
[email protected]
http://lists.ironpython.com/listinfo.cgi/users-ironpython.com