Author Topic: Xref Tools  (Read 11920 times)

0 Members and 1 Guest are viewing this topic.

Chuck Gabriel

  • Guest
Xref Tools
« on: July 09, 2008, 01:57:32 PM »
I thought somebody else might find this useful, plus I thought it might elicit some comments I can learn from.

Code: [Select]
using System;
using System.IO;
using System.Text;

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

using ofdFlags = Autodesk.AutoCAD.Windows.OpenFileDialog.OpenFileDialogFlags;

[assembly: ExtensionApplication(typeof(cgabriel.XrefTools))]
[assembly: CommandClass(typeof(cgabriel.XrefTools))]

namespace cgabriel
{
    public class XrefTools : IExtensionApplication
    {
        #region ExtensionAppImplementation

        public void Initialize() { }
        public void Terminate() { }

        #endregion

        #region Helpers

        public delegate void ProcessSingleXref(BlockTableRecord btr);

        public delegate void ProcessMultipleXrefs(ObjectIdCollection xrefIds);

        public static void detachXref(BlockTableRecord btr)
        {
            Application.DocumentManager.MdiActiveDocument.Database.DetachXref(btr.ObjectId);
        }

        public static void openXref(BlockTableRecord btr)
        {
            string xrefPath = btr.PathName;
            if (xrefPath.Contains("..\\"))
            {
                string hostPath =
                    Application.DocumentManager.MdiActiveDocument.Database.Filename;
                Directory.SetCurrentDirectory(Path.GetDirectoryName(hostPath));
                xrefPath = Path.GetFullPath(xrefPath);
            }
            if (!File.Exists(xrefPath)) return;
            Document doc = Application.DocumentManager.Open(xrefPath, false);
            if (doc.IsReadOnly)
            {
                System.Windows.Forms.MessageBox.Show(
                    doc.Name + " opened in read-only mode.",
                    "OpenXrefs",
                    System.Windows.Forms.MessageBoxButtons.OK,
                    System.Windows.Forms.MessageBoxIcon.Warning);
            }
        }

        public static void bindXrefs(ObjectIdCollection xrefIds)
        {
            Application.DocumentManager.MdiActiveDocument.Database.BindXrefs(xrefIds, false);
        }

        public static void reloadXrefs(ObjectIdCollection xrefIds)
        {
            Application.DocumentManager.MdiActiveDocument.Database.ReloadXrefs(xrefIds);
        }

        public static void unloadXrefs(ObjectIdCollection xrefIds)
        {
            Application.DocumentManager.MdiActiveDocument.Database.UnloadXrefs(xrefIds);
        }

        public static void processXrefs(string promptMessage, ProcessSingleXref process)
        {
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
            TypedValue[] filterList = { new TypedValue(0, "INSERT") };
            ed.WriteMessage(promptMessage);
            PromptSelectionResult result = ed.GetSelection(new SelectionFilter(filterList));
            if (result.Status != PromptStatus.OK) return;

            ObjectId[] ids = result.Value.GetObjectIds();
            Database db = Application.DocumentManager.MdiActiveDocument.Database;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                ObjectIdCollection xrefIds = new ObjectIdCollection();
                foreach (ObjectId id in ids)
                {
                    BlockReference blockRef = (BlockReference)tr.GetObject(id, OpenMode.ForRead, false, true);
                    ObjectId bId = blockRef.BlockTableRecord;
                    if (!xrefIds.Contains(bId))
                    {
                        xrefIds.Add(bId);
                        BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bId, OpenMode.ForRead);
                        if (btr.IsFromExternalReference)
                            process(btr);
                    }
                }
                tr.Commit();
            }
        }

        public static void processXrefs(string promptMessage, ProcessMultipleXrefs process)
        {
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
            TypedValue[] filterList = { new TypedValue(0, "INSERT") };
            ed.WriteMessage(promptMessage);
            PromptSelectionResult result = ed.GetSelection(new SelectionFilter(filterList));
            if (result.Status != PromptStatus.OK) return;

            ObjectId[] ids = result.Value.GetObjectIds();
            Database db = Application.DocumentManager.MdiActiveDocument.Database;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                ObjectIdCollection blockIds = new ObjectIdCollection();
                foreach (ObjectId id in ids)
                {
                    BlockReference blockRef = (BlockReference)tr.GetObject(id, OpenMode.ForRead, false, true);
                    blockIds.Add(blockRef.BlockTableRecord);
                }
                ObjectIdCollection xrefIds = filterXrefIds(blockIds);
                if (xrefIds.Count != 0)
                    process(xrefIds);
                tr.Commit();
            }
        }

        public static void attachXrefs(string[] fileNames)
        {
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
            Array.Sort(fileNames);
            Database db = Application.DocumentManager.MdiActiveDocument.Database;
            double dimscale = db.Dimscale;
            foreach (string fileName in fileNames)
            {
                PromptPointOptions options = new PromptPointOptions("Pick insertion point for " + fileName + ": ");
                options.AllowNone = false;
                PromptPointResult pt = ed.GetPoint(options);
                if (pt.Status != PromptStatus.OK) continue;

                double xrefScale = getDwgScale(fileName);
                double scaleFactor = dimscale / xrefScale;
                using (Transaction tr = Application.DocumentManager.MdiActiveDocument.TransactionManager.StartTransaction())
                {
                    ObjectId xrefId = db.AttachXref(fileName, Path.GetFileNameWithoutExtension(fileName));
                    BlockReference blockRef = new BlockReference(pt.Value, xrefId);
                    BlockTableRecord layoutBlock = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                    blockRef.ScaleFactors = new Scale3d(scaleFactor, scaleFactor, scaleFactor);
                    blockRef.Layer = "0";
                    layoutBlock.AppendEntity(blockRef);
                    tr.AddNewlyCreatedDBObject(blockRef, true);
                    tr.Commit();
                }
            }
        }

        public static double getDwgScale(string fileName)
        {
            using (Database db = new Database(false, true))
            {
                db.ReadDwgFile(fileName, FileOpenMode.OpenForReadAndAllShare, false, string.Empty);
                return db.Dimscale;
            }
        }

        public static ObjectIdCollection filterXrefIds(ObjectIdCollection blockIds)
        {
            Database db = Application.DocumentManager.MdiActiveDocument.Database;
            ObjectIdCollection xrefIds = new ObjectIdCollection();
            foreach (ObjectId bId in blockIds)
            {
                if (!xrefIds.Contains(bId))
                {
                    BlockTableRecord btr = (BlockTableRecord)bId.GetObject(OpenMode.ForRead);
                    if (btr.IsFromExternalReference)
                        xrefIds.Add(bId);
                }
            }
            return xrefIds;
        }

        #endregion

        #region Commands

        [CommandMethod("XrefTools", "AttachXrefs", CommandFlags.Modal | CommandFlags.DocExclusiveLock)]
        public static void XrefAttach()
        {
            string initFolder = Application.DocumentManager.MdiActiveDocument.Database.Filename.ToUpper();
            if (initFolder.Contains("PLOT"))
            {
                initFolder = initFolder.Replace("-PLOT.DWG", "");
                initFolder = initFolder.Replace("PLOT\\", "");
                if (!Directory.Exists(initFolder))
                    initFolder = Application.DocumentManager.MdiActiveDocument.Database.Filename;
            }

            ofdFlags flags = ofdFlags.DefaultIsFolder | ofdFlags.AllowMultiple;
            OpenFileDialog dlg = new OpenFileDialog("Select Drawings to Attach", initFolder, "dwg", "Select Xrefs", flags);
            if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                attachXrefs(dlg.GetFilenames());
        }

        [CommandMethod("XrefTools", "BindXrefs", CommandFlags.Modal | CommandFlags.DocExclusiveLock)]
        public static void XrefBind()
        {
            processXrefs("\nSelect xrefs to bind: ", XrefTools.bindXrefs);
        }

        [CommandMethod("XrefTools", "DetachXrefs", CommandFlags.Modal | CommandFlags.DocExclusiveLock)]
        public static void XrefDetach()
        {
            processXrefs("\nSelect xrefs to detach: ", XrefTools.detachXref);
        }

        [CommandMethod("XrefTools", "OpenXrefs", CommandFlags.Session)]
        public static void XrefOpen()
        {
            processXrefs("\nSelect xrefs to open: ", XrefTools.openXref);
        }

        [CommandMethod("XrefTools", "ReloadXrefs", CommandFlags.Modal | CommandFlags.DocExclusiveLock)]
        public static void XrefReload()
        {
            processXrefs("\nSelect xrefs to reload: ", XrefTools.reloadXrefs);
        }

        [CommandMethod("XrefTools", "ReloadAllXrefs", CommandFlags.Modal | CommandFlags.DocExclusiveLock)]
        public static void XrefReloadAll()
        {
            Database db = Application.DocumentManager.MdiActiveDocument.Database;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable blockTbl = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                ObjectIdCollection blockIds = new ObjectIdCollection();
                foreach (ObjectId bId in blockTbl)
                    blockIds.Add(bId);
                ObjectIdCollection xrefIds = filterXrefIds(blockIds);
                if (xrefIds.Count != 0)
                    db.ReloadXrefs(xrefIds);
                tr.Commit();
            }
        }

        [CommandMethod("XrefTools", "UnloadXrefs", CommandFlags.Modal | CommandFlags.DocExclusiveLock)]
        public static void XrefUnload()
        {
            processXrefs("\nSelect xrefs to unload: ", XrefTools.unloadXrefs);
        }

        #endregion

    }
}

FengK

  • Guest
Re: Xref Tools
« Reply #1 on: July 09, 2008, 02:50:48 PM »
Thanks Chuck. I got an error when trying to compile it:

The name 'FileOpenMode' does not exist in the current context (CS0103)

Do I need to reference other dll's besides acmgd.dll and acdbmgd.dll?


Chuck Gabriel

  • Guest
Re: Xref Tools
« Reply #2 on: July 09, 2008, 02:53:48 PM »
Thanks Chuck. I got an error when trying to compile it:

The name 'FileOpenMode' does not exist in the current context (CS0103)

Do I need to reference other dll's besides acmgd.dll and acdbmgd.dll?

Sorry.  I guess I should have mentioned that this was coded against the AutoCAD 2009 .NET API and that a reference to System.Windows.Forms is also required.

Thanks for taking a look at it, by the way.
« Last Edit: July 09, 2008, 02:57:37 PM by Chuck Gabriel »

FengK

  • Guest
Re: Xref Tools
« Reply #3 on: July 09, 2008, 04:13:40 PM »
Sorry.  I guess I should have mentioned that this was coded against the AutoCAD 2009 .NET API and that a reference to System.Windows.Forms is also required.

Do you mean the code won't work with earlier releases of AutoCAD? (I tested it with AutoCAD 2008). Btw, I did reference System.Windows.Forms.

Chuck Gabriel

  • Guest
Re: Xref Tools
« Reply #4 on: July 09, 2008, 10:47:41 PM »
Sorry.  I guess I should have mentioned that this was coded against the AutoCAD 2009 .NET API and that a reference to System.Windows.Forms is also required.

Do you mean the code won't work with earlier releases of AutoCAD? (I tested it with AutoCAD 2008). Btw, I did reference System.Windows.Forms.

It uses at least one feature that I know doesn't exist in AutoCAD 2007.

Code: [Select]
db.ReadDwgFile(fileName, FileOpenMode.OpenForReadAndAllShare, false, string.Empty);

That particular overload of ReadDwgFile doesn't exist in the 2007 API.  I'm not sure about 2008.
« Last Edit: July 10, 2008, 08:30:36 AM by Chuck Gabriel »

FengK

  • Guest
Re: Xref Tools
« Reply #5 on: July 10, 2008, 01:14:41 AM »
That particular overload of ReadDwgFile doesn't exist in the 2007 API.  I'm not sure about 2008.

My guess is it doesn't exist in AutoCAD 2008 either. I'll confirm it tomorrow. Thanks.

Chuck Gabriel

  • Guest
Re: Xref Tools
« Reply #6 on: July 10, 2008, 06:37:47 AM »
Here is what I've used in the past.  This overload is deprecated according to the 2009 docs.

Code: [Select]
db.ReadDwgFile(fileName, System.IO.FileShare.Read, false, string.Empty);

FengK

  • Guest
Re: Xref Tools
« Reply #7 on: July 10, 2008, 01:18:13 PM »
Here is what I've used in the past.  This overload is deprecated according to the 2009 docs.
Code: [Select]
db.ReadDwgFile(fileName, System.IO.FileShare.Read, false, string.Empty);

This works with AutoCAD 2008. And the original overloaded version does not seem to available in 2008. Attached is from acad_mgd.chm for version 2008.

The OpenXrefs command doesn't seem to do anything.

Thanks Chuck.

Chuck Gabriel

  • Guest
Re: Xref Tools
« Reply #8 on: July 10, 2008, 02:25:38 PM »
Attached is from acad_mgd.chm for version 2008.

I know there has been a lot of grumbling about 2009, but I will say this.  The documentation for the managed API is a lot better in 2009.

The OpenXrefs command doesn't seem to do anything.

Are your xrefs relative-pathed by any chance?  I ask because the following line might cause it to to seem like a no-op if I've gotten my path resolution code wrong:

Code: [Select]
if (!File.Exists(xrefPath)) return;

I can't remember whether I ever actually got around to testing this bit:

Code: [Select]
if (xrefPath.Contains("..\\"))
{
  string hostPath =
    Application.DocumentManager.MdiActiveDocument.Database.Filename;
  Directory.SetCurrentDirectory(Path.GetDirectoryName(hostPath));
  xrefPath = Path.GetFullPath(xrefPath);
}

Thanks again for looking at it Kelie.
« Last Edit: July 10, 2008, 02:35:06 PM by Chuck Gabriel »

FengK

  • Guest
Re: Xref Tools
« Reply #9 on: July 10, 2008, 09:33:29 PM »
Are your xrefs relative-pathed by any chance?  I ask because the following line might cause it to to seem like a no-op if I've gotten my path resolution code wrong:

Yes. I prefer using relative paths.

I can't remember whether I ever actually got around to testing this bit:

Code: [Select]
if (xrefPath.Contains("..\\"))

Change "..\\" to ".\\" fixes the problem.

Thanks again for looking at it Kelie.
My pleasure. You've done the hard work and I get to learn a little bit of C#.

Glenn R

  • Guest
Re: Xref Tools
« Reply #10 on: July 11, 2008, 04:36:18 AM »
Hey Chuck,

Nice stuff - especially the relative path resolution. Can you try your bind function on the drawings I posted in this thread and see what happens please?

Cheers,
Glenn.

Chuck Gabriel

  • Guest
Re: Xref Tools
« Reply #11 on: July 11, 2008, 07:12:54 AM »
Change "..\\" to ".\\" fixes the problem.

I should have thought of that.  Thanks for the tip.


Hey Chuck,

Nice stuff - especially the relative path resolution. Can you try your bind function on the drawings I posted in this thread and see what happens please?

Cheers,
Glenn.

I'll try it when I get home.

Chuck Gabriel

  • Guest
Re: Xref Tools
« Reply #12 on: July 11, 2008, 10:36:12 AM »
I'll try it when I get home.

I just realized I'm not going to be able to do this.  The function I used isn't available in 2007 and my trial of 2009 has expired.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: Xref Tools
« Reply #13 on: July 12, 2008, 02:26:07 PM »
You do very nice programming Chuck!
The only thing I might consider changing is, the function filterXrefIds()  assigns the variable ‘Database db’ that’s not used. 

Chuck Gabriel

  • Guest
Re: Xref Tools
« Reply #14 on: July 12, 2008, 02:44:47 PM »
You do very nice programming Chuck!

Thanks.

The only thing I might consider changing is, the function filterXrefIds()  assigns the variable ‘Database db’ that’s not used. 

I wonder where I was planning on going with that.  Thanks for pointing it out.

Glenn R

  • Guest
Re: Xref Tools
« Reply #15 on: July 12, 2008, 03:45:42 PM »
BTW, nice delegation there Chuck :)

Spike Wilbury

  • Guest
Re: Xref Tools
« Reply #16 on: July 12, 2008, 06:32:37 PM »
Chuck is the man.... I learn a lot from him, in my early C++ and ObjectARX digesting days - from you too Glenn, the man2.  :)

Chuck Gabriel

  • Guest
Re: Xref Tools
« Reply #17 on: July 12, 2008, 08:18:31 PM »
Thanks for the kind words guys.

Glenn R

  • Guest
Re: Xref Tools
« Reply #18 on: July 13, 2008, 04:26:27 AM »
Hey Luis, good to see you again.

autocart

  • Guest
Re: Xref Tools
« Reply #19 on: August 03, 2011, 03:04:31 AM »
Hi, I hope nobody minds the push since it relates directly (so in case someone ever has the same problem it is handled right here).

I cant get the code to work. I use Autocad 2011 with VS 2010 EE and the "AutoCAD 2011 .Net Wizards" from the Developer Center. All that on Win7 64 bit. Everything in German.

Debug starts fine, Autocad starts up. I can netload without problems.
But now, when I type attachxrefs, Autocad seems to do nothing and hangs. Nothing happens anymore. The only thing I can do is to end the debugging.
Or, when I type bindxrefs, then I get asked "Select xrefs to bind: " but as soon as I move the mouse or press a button I get an Autocad-error-message saying "SYSTEM ERROR: Unsupported version of Windows Presentation Foundation".

Does anybody have an idea? Thx.

EDIT:

Sorry for the bother. I found the solution: The compiled dll may not be located on a network drive but must be local.
See also:
http://blog.jtbworld.com/2009/03/fatal-error-unsupported-version-of.html
and
http://www.cadtutor.net/forum/showthread.php?51395-VB.Net&s=5ef6ab1938a8d29d4590a757b34afe71
« Last Edit: August 03, 2011, 03:39:48 AM by autocart »

airportman

  • Newt
  • Posts: 37
  • i customize when required
Re: Xref Tools
« Reply #20 on: March 04, 2013, 06:44:41 PM »
Autocart:

I too had this same issue with another DLL that I was able make work on my laptop, but never on my desktop. Turns out, the dll had to be local.

cheers,
Perception is a state of mind  -/ Twitter = @hochanz -/ Intel i7 - 3.07GHz -/ 12GB Ram -/ Nvidia Quadro FX 1800