Author Topic: Expose ARX Function to .NET  (Read 22808 times)

0 Members and 1 Guest are viewing this topic.

TR

  • Guest
Re: Expose ARX Function to .NET
« Reply #15 on: August 24, 2007, 10:28:21 AM »
Thanks, I'll give it a shot. I don't know if I can use the ARX templates from Autodesk so I might have to manually recreate the template. I don't think I was able to get the templates to install correctly with Visual C++ Express 2005.

TR

  • Guest
Re: Expose ARX Function to .NET
« Reply #16 on: August 24, 2007, 12:17:34 PM »
Got the templates to work correctly with C++ Express. However now I'm missing tons of header files and I guess I have to download a 1+GB SDK to get windows.h. Am I wrong? I searched my system for the file and it was nowhere to be found.

It's Alive!

  • BricsCAD
  • Needs a day job
  • Posts: 7047
  • AKA Daniel
Re: Expose ARX Function to .NET
« Reply #17 on: August 24, 2007, 01:03:40 PM »
I have put Mick's wrapper in a VS2005 solution and compiled it for Acad2008
you can test it by running the pyver command.

TR

  • Guest
Re: Expose ARX Function to .NET
« Reply #18 on: August 24, 2007, 01:28:04 PM »
Great, thanks a lot. Now I referenced it in C# and I can call the command but I don't really understand all the argument it's looking for. Any way I could get a sample of how to use it in C#?

It's Alive!

  • BricsCAD
  • Needs a day job
  • Posts: 7047
  • AKA Daniel
Re: Expose ARX Function to .NET
« Reply #19 on: August 24, 2007, 02:50:08 PM »
Here is another one that includes wrappers for acedDefun as PyDefun and acedUndef as PyUnDef.

Honestly, I don’t know enough about IronPython to be able to give an example.
But now we have a couple of ways to register a command name,
now we just need to figure out how to invoke PyAcad.NET functions when the command is called.

TR

  • Guest
Re: Expose ARX Function to .NET
« Reply #20 on: August 24, 2007, 03:10:38 PM »
I don't need an example in IronPython. If you can give me an example of how to use these to wrap a simple C# function like the follow it would be great. I will be able to translate it to IronPython.

Code: [Select]
static public void testcommand()
{
ed.WriteMessage("Command Test Worked!");
}

MickD

  • Gator
  • Posts: 3441
  • (x-in)->[process]->(y-out)
Re: Expose ARX Function to .NET
« Reply #21 on: August 24, 2007, 08:50:21 PM »
an example -
IronPyCommandReg.RegisterCommand("timsapp","TEST","TESTINSPANISH",CMD_MODAL,testcommanddelegate)


to use the dll, all you need to do is add a ref into your project and call IronPyCommandReg.RegisterCommand("mygroup","myglobalcommandname","mylocalcomname",CMD_MODAL,mydotnetfuncname)
It's a static function so you don't need to create an instance, just use the class name then the '.' operator to call the function
where the 'group' is your application group, you add any commands you register to this group typically, global and local names are the command names that you issue at the command promt such as MYLINE, the command flags are just that, you can 'or' them together using the '|' operator, the last param is the function name that acad calls (the callback) when someone enters the command, you may need to create a delegate to pass to this function to work (most probably, a delegate is basically a function pointer used for callbacks).

You need to use that function for every command you want to register before you can use them, what it does is like I just explained, it registers the command name in a stack along with the function (address of) to call. You would typically do this when you load your dll into acad using the IExtensionblah blah (sorry, I forget) interface.

Like I said before, I have no idea if the callback will work but lets see, I also have no idea what Daniel has done with the code with all the '^''s :( It seems MS have done another good job of bastardizing a good language  :roll: but if it works .....
« Last Edit: August 24, 2007, 08:52:33 PM by MickD »
Forth is like the Tao: it is a Way, and is realized when followed.
Its fragility is its strength; its simplicity is its direction - Michael Ham

Lao Tzu: “To attain knowledge, add things
every day; to obtain wisdom, remove things every day.”

MickD

  • Gator
  • Posts: 3441
  • (x-in)->[process]->(y-out)
Re: Expose ARX Function to .NET
« Reply #22 on: August 24, 2007, 09:25:43 PM »
Actually, if anyone has some spare time this can be used from C# also, should be a good exercise in creating and using delegates ;)
Forth is like the Tao: it is a Way, and is realized when followed.
Its fragility is its strength; its simplicity is its direction - Michael Ham

Lao Tzu: “To attain knowledge, add things
every day; to obtain wisdom, remove things every day.”

TR

  • Guest
Re: Expose ARX Function to .NET
« Reply #23 on: August 25, 2007, 01:07:00 PM »
Ok I was doing some testing just now and here is what I have. From a C# project I refereneced the mixed dll that Daniel has so kindly compiled for me. In my class I declared a public delegate like so:
Code: [Select]
public delegate void TestDelegate(); I then added the following code to the project:
Code: [Select]
      [CommandMethod("testreg", CommandFlags.Session)]
      static public void testreg()
      {
          TestDelegate testmycommand = new TestDelegate(testcommand);

          IronPy.CommandReg.IronPyCommandReg.RegisterCommand("tester", "testcommand", "testcommand", IronPy.CommandReg.IronPyCommandReg.CMD_MODAL, testmycommand());
      }

      static public void testcommand()
      {
          ed.WriteMessage("Command Test Worked!");
      }

When I got to build I get the following two errors:
Quote
Error   1   The best overloaded method match for 'IronPy.CommandReg.IronPyCommandReg.RegisterCommand(string, string, string, int, System.IntPtr)' has some invalid arguments   C:\Documents and Settings\TJRiley\My Documents\pyacaddotnet\PyAcadDotNet.cs   110   11   PyAcadDotNet
Error   2   Argument '5': cannot convert from 'void' to 'System.IntPtr'   C:\Documents and Settings\TJRiley\My Documents\pyacaddotnet\PyAcadDotNet.cs   110   148   PyAcadDotNet
So from there I see that a delegate isn't going to work and I'll have to use pointers in my C# code and compile it with the unsafe flag. Am I correct?

MickD

  • Gator
  • Posts: 3441
  • (x-in)->[process]->(y-out)
Re: Expose ARX Function to .NET
« Reply #24 on: August 25, 2007, 06:48:35 PM »
What we need to find out is how to pass a delegate to native code and it won't be trivial but it can be done. There should be no need for unsafe code as that part is handled with the dll.

Here's a link to something that should work, Daniel may have time over the weekend to have a look, hope it helps.

BTW, because you are registering the command using the new reg command function you no longer need the CommandMethod attributes, you may want to change the flag from CMD_MODAL to CMD_SESSION if that's what you need ;)
« Last Edit: August 25, 2007, 06:52:13 PM by MickD »
Forth is like the Tao: it is a Way, and is realized when followed.
Its fragility is its strength; its simplicity is its direction - Michael Ham

Lao Tzu: “To attain knowledge, add things
every day; to obtain wisdom, remove things every day.”

MickD

  • Gator
  • Posts: 3441
  • (x-in)->[process]->(y-out)
Re: Expose ARX Function to .NET
« Reply #25 on: August 25, 2007, 07:03:52 PM »
Just thinking about it I can't see why you can't just use P/Invoke ?!?

The issue is the same but saves a lot of messing around with a dll and 'hoping' we're doing it right!

I'll have a look around and see what turns up.
Forth is like the Tao: it is a Way, and is realized when followed.
Its fragility is its strength; its simplicity is its direction - Michael Ham

Lao Tzu: “To attain knowledge, add things
every day; to obtain wisdom, remove things every day.”

MickD

  • Gator
  • Posts: 3441
  • (x-in)->[process]->(y-out)
Re: Expose ARX Function to .NET
« Reply #26 on: August 25, 2007, 07:13:31 PM »
Have a look through this, it gives you a simple a example of what you need to do, in your case it's easier as you don't need to marshal parameters, the other hard part may be finding the 'scrambled' function name as it calls a C++ class method.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconcallbacksample.asp
Forth is like the Tao: it is a Way, and is realized when followed.
Its fragility is its strength; its simplicity is its direction - Michael Ham

Lao Tzu: “To attain knowledge, add things
every day; to obtain wisdom, remove things every day.”

LE

  • Guest
Re: Expose ARX Function to .NET
« Reply #27 on: August 25, 2007, 07:33:52 PM »
I just tried to follow what it is in here:

http://through-the-interface.typepad.com/through_the_interface/2006/07/calling_objecta.html

With the latest arx code I have.... but I have to place the my arx where the acad.exe is located and appears that I need to copy those dll's in the same spot.... will see if works...

TR

  • Guest
Re: Expose ARX Function to .NET
« Reply #28 on: August 25, 2007, 11:08:17 PM »
When I discussed this with Kean Walmsley he said it wasn't possible to access this through P/Invoke. Below are the emails exchanged between us. Hopefully they will help out.
Quote
Tim Riley <riltim@gmail.com>    Wed, Aug 22, 2007 at 9:45 PM
To: kean.walmsley@autodesk.com
Kean:

I am working on an open source project[1] to allow to the use of
Python as as a programming language for AutoCAD 2008 via
IronPython[2]. The code I have now compiles and I am able to
manipulate AutoCAD via the .NET API through code run from a python
file, which I never thought I could do. However the next task I need
to tackle before I'm 100% confident this is a worthwhile project to
devote a great deal of my time to is register AutoCAD commands via
code. IronPython doesn't support .NET attributes and probably never
will. This leaves me with the daunting task of somehow figure out a
way to register command line commands through code instead of the
CommandMethod attribute.

I have asked around on the newsgroups with little success. The best I
was able to receive was advice about System.Reflection. But since my
code is compiled in memory within a hosted application I'm thinking
this isn't the way I need to be going. I know the CommandMethod
attribute is just a wrapper for some function, I just can't figure out
what that function is and how to make my python stuff command line
callable.

Any pointers you could give me on this subject would be greatly appreciated.

Thanks,
Tim Riley

[1] http://code.google.com/p/pyacaddotnet/
[2] http://www.codeplex.com/IronPython
Kean Walmsley <kean.walmsley@autodesk.com>    Thu, Aug 23, 2007 at 4:21 AM
To: Tim Riley <riltim@gmail.com>
Tim,

The underlying ObjectARX (C++) function used to register a command is
AcEdCommandStack::addCommand(). There's typically only one
AcEdCommandStack in an AutoCAD session, which is generally accessed from
C++ via the acedRegCmds macro:

acedRegCmds->addCommand("CMD_GROUP", "GLOBAL_CMD_NAME",
"LOCAL_CMD_NAME", ACRX_CMD_MODAL | ACRX_CMD_USEPICKSET, func1);

I don't know whether it's possible to access this from IronPython - I
suspect you might need to include a small ObjectARX module that exposes
a C function or implements a managed wrapper that IronPython can call.

Cheers,

Kean
[Quoted text hidden]
Tim Riley <riltim@gmail.com>    Thu, Aug 23, 2007 at 9:35 AM
To: Kean Walmsley <kean.walmsley@autodesk.com>
Kean:

Thanks for the reply.

So if I understand what you said correctly AutoCAD's .NET
CommandMethod attribute uses the ARX AcEdCommandStack::addCommand()
function to register command line callable commands? If so I'm
assuming that I could also wrap the ARX command in C#, correct? As
long as I can get a function in C# to register a command I can use it
in IronPython as I can pass .NET objects to my IronPython.Engine and
then use them in my Python code.

Thanks,
Tim
[Quoted text hidden]
Kean Walmsley <kean.walmsley@autodesk.com>    Thu, Aug 23, 2007 at 10:00 AM
To: Tim Riley <riltim@gmail.com>
Tim,

Yes - this is ultimately how .NET-defined commands are registered. Our
managed wrapper (a mixed mode module) calls through to the C++ API to
register commands.

But calling this from C# is not that easy: the class is not exposed
directly - the way to register commands is via attributes - and as this
is a class method there's no way to P/Invoke it directly.

Cheers,

Kean

-----Original Message-----
From: Tim Riley [mailto:riltim@gmail.com]
[Quoted text hidden]
Tim Riley <riltim@gmail.com>    Thu, Aug 23, 2007 at 11:21 AM
To: Kean Walmsley <kean.walmsley@autodesk.com>
Kean:

So just to be clear I would have to write an ARX wrapper around
AcEdCommandStack::addCommand() and expose it .NET? Then I would be
able to access it from C# and ultimately IronPython?

I've never attempted to create a C++ ARX file, is it safe to assume I
can do this with the C++ express edition or do I need to get full
blown visual studio?

Thanks again for your help.
[Quoted text hidden]
Kean Walmsley <kean.walmsley@autodesk.com>    Fri, Aug 24, 2007 at 2:31 AM
To: Tim Riley <riltim@gmail.com>
Tim,

You could either expose it via .NET (by implementing a mixed-mode
module), or simply export a standard C-style function which you can then
P/Invoke from .NET (which would be much easier).

You should be able to use C++ Express, although I haven't done so
myself.

Regards,

Kean

LE

  • Guest
Re: Expose ARX Function to .NET
« Reply #29 on: August 25, 2007, 11:40:09 PM »
Tim;

I have no idea about IronPython at all but, found this "using IronPython from C#"

http://www.mail-archive.com/users@lists.ironpython.com/msg01983.html

Might help....

Original code it is available at the url link above.

Make a C# wrapper for a  Python class ...
Code: [Select]
class LogViewerService
{
         public delegate int GetNumberOfEntriesDelegate();
         public GetNumberOfEntriesDelegate GetNumberOfEntries;

         public delegate object GetEntryDelegate(int entryNumber);
         public GetEntryDelegate GetEntry;

         public delegate void closeDelegate();
         public closeDelegate close;

         public LogViewerService(object pythonObject)
         {
             object method;
             IronPython.Runtime.Operations.Ops.TryGetAttr (pythonObject, IronPython.Runtime.SymbolTable.StringToId ("GetNumberOfEntries"), out method);
             GetNumberOfEntries = (GetNumberOfEntriesDelegate) IronPython.Runtime.Operations.Ops.GetDelegate(method, typeof (GetNumberOfEntriesDelegate));
             IronPython.Runtime.Operations.Ops.TryGetAttr (pythonObject, IronPython.Runtime.SymbolTable.StringToId("GetEntry"),  out method);
             GetEntry = (GetEntryDelegate) IronPython.Runtime.Operations.Ops.GetDelegate(method, typeof (GetEntryDelegate));
             IronPython.Runtime.Operations.Ops.TryGetAttr (pythonObject, IronPython.Runtime.SymbolTable.StringToId("close"),  out method);
             close = (closeDelegate) IronPython.Runtime.Operations.Ops.GetDelegate(method, typeof (closeDelegate));
         }
 }
« Last Edit: August 25, 2007, 11:46:19 PM by LE »