Author Topic: Assembly Test Request  (Read 7729 times)

0 Members and 1 Guest are viewing this topic.

TR

  • Guest
Re: Assembly Test Request
« Reply #15 on: January 23, 2007, 01:50:23 PM »
Thanks a lot Dan. It's somewhat comforting that the code is working with newer versions of AutoCAD (with only a slight modification and recompile by you). The first file you ran is supposed to dump all the layer names to the command line, I assume you were on a new drawing and that's why it only dumped '0'. Also I assume you saw a windows form when running winforms.py.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8722
  • AKA Daniel
Re: Assembly Test Request
« Reply #16 on: January 23, 2007, 01:55:01 PM »
Yes sir you got it. Pretty interesting project.
Dan

TR

  • Guest
Re: Assembly Test Request
« Reply #17 on: January 23, 2007, 02:11:19 PM »
Thanks. The goal is to give AutoCAD programmers the ability to use AutoCAD's .NET API with any .NET library and/or almost any Python library (as long as it wasn't written in C). The real advantage is the ability to quickly hack up and test code without bothering with building, launching AutoCAD and testing. Instead we can just test, fix, test, fix, test, fix, etc. in a single session of AutoCAD.

The current stage is more of a proof of concept than anything but hopefully it can reach a point when it's production ready. However if you find the project interesting you are more than welcome to hack on it if you want.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8722
  • AKA Daniel
Re: Assembly Test Request
« Reply #18 on: January 23, 2007, 02:12:51 PM »
I just noticed an error when I closed the drawing though. I will run each one to see if I can’t find the culprit


FATAL ERROR:  Unhandled Access Violation Reading 0xf0000000 Exception at 136b23ch

01/23/2007 at 12:10:20.666  Drawing:
-------------

TR

  • Guest
Re: Assembly Test Request
« Reply #19 on: January 23, 2007, 07:58:17 PM »
You can probably attribute that error to sloppy translations of C# to python for the examples on my part. I did them rather quickly.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8722
  • AKA Daniel
Re: Assembly Test Request
« Reply #20 on: January 24, 2007, 02:22:16 AM »
I did find the error, it was in layer.py not disposing the transaction manager.

I also made a few mods to your code just for fun(for 2007). I added using() to PythonEngine and AcadCommandLine because they are both disposable


Code: [Select]
/*
PyAcadDotNet.cs
Copyright (c) 2005, Tim Riley (riltim@gmail.com)
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are
permitted provided that the following conditions are met:

- Redistributions of source code must retain the above copyright notice, this list
  of conditions and the following disclaimer.

- Redistributions in binary form must reproduce the above copyright notice, this list
  of conditions and the following disclaimer in the documentation and/or other materials
  provided with the distribution.

- Neither the name Tim Riley nor the names of its contributors may be used to
  endorse or promote products derived from this software without specific prior written
  permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &AS IS& AND ANY EXPRESS
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections;
using System.Windows.Forms;
using System.IO;
using System.Text;

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Interop;
using Autodesk.AutoCAD.Interop.Common;
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 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.Import("clr");

            //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;
      }
    }
  }
}


TR

  • Guest
Re: Assembly Test Request
« Reply #21 on: January 24, 2007, 10:58:24 AM »
Dan:

That looks really good. I'm really not too good with C# so thanks for fixing those few problems.

Seeing that that only thing that's stopping this code file from being compiled for both AutoCAD 2005 and 2006/2007 is the way it interacts with AutoCAD's command line. Is there any way to check what versions of acmgd.dll we're compiling against and issue the correct interface to the command line that way. This way we would could keep everyone working on a single project instead of forking it to run on 2007. I'm not sure if my compiler will complain though about missing assemblies.

MickD

  • King Gator
  • Posts: 3637
  • (x-in)->[process]->(y-out) ... simples!
Re: Assembly Test Request
« Reply #22 on: January 24, 2007, 03:49:38 PM »
The problem is Tim that when acad loads the assembly it will look into the metadata in your dll to find the dependencies which means it will only work with a certain version of the assembly it was compiled with (it will look for the same version that version of acad uses). This is to avoid the dll hell of the past and means you can have various versions of the same assembly in the GAC without conflicts, it looks at each to find the correct version using reflection/metadata or similar.
So, the short answer is you will either need a separate project for each version or you will need some funky pre-processor code to 'switch' which versions you wish to compile to use the appropriate code, either way you will need the assemblies for each version of acad and produce a separate dll for each version. You will need them as you are 'using' them in your C# code.
hth
« Last Edit: January 24, 2007, 03:50:56 PM by MickD »
"Programming is really just the mundane aspect of expressing a solution to a problem."
- John Carmack

"Short cuts make long delays,' argued Pippin.”
- J.R.R. Tolkien

Draftek

  • Guest
Re: Assembly Test Request
« Reply #23 on: January 24, 2007, 04:39:03 PM »
Yeah, The only other option I could think of is late binding but I wouldn't recommend it for much interaction. I have an example posted somewhere here....

I have a detail library program in which the only autocad function is to insert a drawing. I used late binding in c# and it works with v2000 - v2007.

TR

  • Guest
Re: Assembly Test Request
« Reply #24 on: January 24, 2007, 05:29:31 PM »
Mick:

I'm not looking for a single .dll to run across all across all versions of AutoCAD but instead a project that will compile against newer versions of the .NET managed assemblies. I'm fine distributing a seperate dll for each version of AutoCAD. So far the only conflict I'm having in the project is it's interaction with AutoCAD's command line. In fact the C# project will be doing very minimal interaction with AutoCAD's managed libraries. The python files will but that's beyond the scope of the C# project.

In the python world we can do tricks like:
Code: [Select]
try:
    import LatestAndGreatestLib
except importerror:
   import OlderAndLessGreatLib
   'some code that will make it somewhat compatible with the new lib

This allows you to use the newer version of the library if it's available but fall back upon an older lib if necessary.

Can we do something like this?:
Code: [Select]
try
{
    using AcEd = Autodesk.AutoCAD.EditorInput;
}
catch (System.Exception e)
{
    //some code here to make it compatible.
}
« Last Edit: January 24, 2007, 05:30:32 PM by Tim Riley »