Author Topic: Open, Bind and Close  (Read 18015 times)

0 Members and 1 Guest are viewing this topic.

mcarson

  • Guest
Re: Open, Bind and Close
« Reply #15 on: August 20, 2008, 06:31:15 AM »
Made another change: commented out the block that checks for resolved xrefs, and it worked. :?

Code: [Select]
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using AppServices = Autodesk.AutoCAD.ApplicationServices;

public class clsBindSupport : Autodesk.AutoCAD.Runtime.IExtensionApplication
{
   
   
    public void Autodesk.AutoCAD.Runtime.IExtensionApplication.Initialize()
    {
    }
   
    public void Autodesk.AutoCAD.Runtime.IExtensionApplication.Terminate()
    {
    }
   
    public clsBindSupport()
    {
        //Does nothing...
    }
   
    [CommandMethod("exBind")]
    public static void ExBind()
    {
        //Get the currently active document
        AppServices.Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
        //Get the document's database
        Database db = doc.Database;
        //Get the editor
        Editor ed = doc.Editor;
        //Get the path to the document
        string dwgprefix = Autodesk.AutoCAD.ApplicationServices.Application.GetSystemVariable("DWGPREFIX").ToString;
        //Get the name of the document
        string dwgname = Autodesk.AutoCAD.ApplicationServices.Application.GetSystemVariable("DWGNAME").ToString;
        //Strip the file extension from the document name
        string dwgtitle = Strings.Mid(dwgname, 1, Strings.Len(dwgname) - 4);
        //Create the new file name
        string newdwgfile = dwgprefix + dwgtitle + "_bound" + ".dwg";
       
        //Create a new database, reading the current drawing
        Database newdb = new Database(false, true);
        newdb.ReadDwgFile(doc.Name, IO.FileShare.ReadWrite, true, null);
       
        //Get the xref graph
        XrefGraph xrefGraph = newdb.GetHostDwgXrefGraph(true);
        //Check for xrefs
        if (xrefGraph == null || xrefGraph.IsEmpty || xrefGraph.NumNodes == 1) {
            ed.WriteMessage("" + Strings.Chr(10) + "No xrefs found.");
            newdb.Dispose();
            return;
        }
       
        //Problem occurred in the following If block. Couldn't resolve xrefs in the in-memory database
        //Comment it out to demonstrate the method working
       
        //TODO: Resolve xrefs on the original database before new database is created??
       
        //Check for unresolved xrefs
        if (xrefGraph.MarkUnresolvedTrees()) {
            ed.WriteMessage("" + Strings.Chr(10) + "Error: There are unresolved xrefs - bind aborted!");
            newdb.Dispose();
            return;
        }
       
       
       
       
        for (int i = 0; i <= xrefGraph.NumNodes - 1; i++) {
            XrefGraphNode xrefGraphNode = xrefGraph.GetXrefNode(i);
            if (xrefGraphNode == null) {
                ed.WriteMessage("" + Strings.Chr(10) + "Error: Failed to get a node on the graph - aborting!");
                newdb.Dispose();
                return;
            }
           
            // Is it the root node, which is the current drawing?
            // If it IS, then the number of incoming nodes will be 0...
            if (xrefGraphNode == xrefGraph.HostDrawing) {
                continue;
            }
           
            // Continue if it's truly nested as we can only bind "true" top level parents...
            if (xrefGraphNode.IsNested) {
                continue;
            }
           
            if (xrefGraphNode.NumIn == 1) {
               
                string xrefName = null;
                ObjectId xrefid;
               
                using (Transaction tr = newdb.TransactionManager.StartTransaction()) {
                   
                    BlockTableRecord btr = tr.GetObject(xrefGraphNode.BlockTableRecordId, OpenMode.ForRead, false) as BlockTableRecord;
                    if (btr == null) {
                        ed.WriteMessage("" + Strings.Chr(10) + "Error: Failed to get xref name - aborting!");
                        newdb.Dispose();
                        return;
                    }
                   
                    xrefName = btr.Name;
                    xrefid = btr.ObjectId;
                }
               
                if (xrefName != null) {
                   
                    ed.WriteMessage("" + Strings.Chr(10) + "Binding xref {0}...", xrefName);
                   
                    //acedXrefBind(xrefName, False, False, IntPtr.Zero)
                    ObjectIdCollection ids = new ObjectIdCollection();
                    ids.Add(xrefid);
                    newdb.BindXrefs(ids, true);
                   
                }
               
            }
        }
        //Copy the preview bitmap from the original database
        newdb.RetainOriginalThumbnailBitmap = true;
        //Save the new drawing file
        newdb.SaveAs(newdwgfile, DwgVersion.Current);
        //Destroy the database, as we no longer need it
        newdb.Dispose();
    }
}

Read the comments in the code - may work, just need to make the changes.

260 users; the good thing at the moment is that only 10% know I exist.
the bad thing is that after I deploy AutoCAD 2008, the other 90% will...
With CAD standards (wrong forum, sorry) the hardest thing is getting everyone to change.

Glenn R

  • Guest
Re: Open, Bind and Close
« Reply #16 on: August 20, 2008, 06:46:22 AM »
Before even putting it in the IDE, I notice that you are still issuing BindXrefs inside a for loop - move it outside and call it once.

Change is easy - just keep getting a bigger stick until it sticks :D

Glenn R

  • Guest
Re: Open, Bind and Close
« Reply #17 on: August 20, 2008, 09:54:50 AM »
Give this a whirl:

Code: [Select]
using System;
using System.IO;
using System.Runtime.InteropServices;

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

using acadApp = Autodesk.AutoCAD.ApplicationServices.Application;

namespace XrefBind
{
public class Class1
{
[DllImport("acdb17.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode,
EntryPoint = "?acdbBindXrefs@@YA?AW4ErrorStatus@Acad@@PAVAcDbDatabase@@ABV?$AcArray@VAcDbObjectId@@V?$AcArrayMemCopyReallocator@VAcDbObjectId@@@@@@_N22@Z")]
extern public static ErrorStatus acdbBindXrefs(IntPtr pHostDb, IntPtr xrefObjectIds, bool bInsertBind, bool bAllowUnresolved, bool bQuiet);

// Define Command "BAX"
[CommandMethod("tcgsBAX")]
static public void BindAllXrefsCommand()
{
// Get the usual
Document doc = acadApp.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;

// Has the drawing been saved?
if ((short)acadApp.GetSystemVariable("DBMOD") != 0)
{
ed.WriteMessage("{0}Drawing must be saved before continuing - please save the drawing and try again.",
Environment.NewLine);
return;
}

// Dbase for our bind
Database dbBind = null;
ObjectIdCollection xrefIds = null;

try
{
// Create the bind host dbase and read our dwg into it
dbBind = new Database(false, true);
dbBind.ReadDwgFile(db.Filename, System.IO.FileShare.ReadWrite, false, null);

// Resolve any xrefs
dbBind.ResolveXrefs(true, false);

// Get the xref graph for the current dbase...
XrefGraph xrefGraph = dbBind.GetHostDwgXrefGraph(true);
if (xrefGraph == null || xrefGraph.IsEmpty || xrefGraph.NumNodes == 1)
{
ed.WriteMessage("{0}No xrefs found.", Environment.NewLine);
return; // No xrefs...
}

// Not allowing unresolved xrefs, however we could by changing
// 4th argument to true of acdbBindXrefs
if (xrefGraph.MarkUnresolvedTrees())
{
ed.WriteMessage("\nWarning: There are unresolved xrefs - bind aborted!");
return;
}

for (int i = 0; i < xrefGraph.NumNodes; i++)
{
XrefGraphNode xrefGraphNode = xrefGraph.GetXrefNode(i);
if (xrefGraphNode == null)
{
ed.WriteMessage("\nError: Failed to get a node on the graph - aborting!");
return;
}

// Is it the root node, which is the current drawing?
// If it IS, then the number of incoming nodes will be 0...
if (xrefGraphNode == xrefGraph.HostDrawing)
continue;

// Continue if it's truly nested as we can only bind "true" top level parents...
if (xrefGraphNode.IsNested)
continue;

if (xrefGraphNode.NumIn == 1)
{
if (xrefIds == null)
xrefIds = new ObjectIdCollection();

xrefIds.Add(xrefGraphNode.BlockTableRecordId);
}

}//for

ErrorStatus es = ErrorStatus.OK;
// Try to bind
es = acdbBindXrefs(dbBind.UnmanagedObject, xrefIds.UnmanagedObject, true, false, false);

string fullFileName = dbBind.Filename;
string filePath = Path.GetDirectoryName(fullFileName);
string fileName = Path.GetFileNameWithoutExtension(fullFileName);
string timeStamp = DateTime.Now.ToString("yyyy-MM-dd_hh-mm-ss");

string newFileName = Path.Combine(filePath, fileName + "_" + timeStamp + ".dwg");
// try to save
dbBind.RetainOriginalThumbnailBitmap = true;
dbBind.SaveAs(newFileName, DwgVersion.Current);

}
catch (System.Exception ex)
{
ed.WriteMessage("{0}Error: {1}", Environment.NewLine, ex.Message);
}
finally
{
if (dbBind != null)
dbBind.Dispose();
}
}
}
}

Usual disclaimer applies - "all care taken, no responsibility implied". Test on copies of live data etc.

Spike Wilbury

  • Guest
Re: Open, Bind and Close
« Reply #18 on: August 20, 2008, 10:07:40 AM »
As always .... Molto bene.

I have a bunch of functions to be translated to C#.... where can I sent those ones....  :evil:    :-P

Glenn R

  • Guest
Re: Open, Bind and Close
« Reply #19 on: August 20, 2008, 10:13:19 AM »
Thanks Luis...I think ;)

I stewed over the DllImport signature for quite a while. I will have to dig deeper into P/Invoke me thinks.

mcarson

  • Guest
Re: Open, Bind and Close
« Reply #20 on: August 20, 2008, 01:05:28 PM »
no emoticon for speechless?!
How'd you do that?
I think I'll wait till I learn a bit more of the .NET API.

Spike Wilbury

  • Guest
Re: Open, Bind and Close
« Reply #21 on: August 20, 2008, 01:56:47 PM »
no emoticon for speechless?!
How'd you do that?
I think I'll wait till I learn a bit more of the .NET API.



FYI

Glenn is a master :)



Glenn R

  • Guest
Re: Open, Bind and Close
« Reply #22 on: August 20, 2008, 03:59:11 PM »
Thanks for the kind words Luis - I don't get out much ;)

I still remember seeing your lisp code back in the day (and still) and you are the master where that's concerned :)

Glenn R

  • Guest
Re: Open, Bind and Close
« Reply #23 on: August 20, 2008, 04:09:32 PM »
How'd you do that?

20+ years of experience in programming AutoCAD with Lisp, VBA, C++/ARX and .NET. I must admit, the C++/ARX background does help a great deal, as I'm sure Luis, MickD, Chuck, Dan and others can attest to.

Credit where credit is due - Microsoft's rationalisation of all their disparate API's (raw C WIN32, COM/COM+/DCOM, C++, ATL, MFC etc.) into an 'object oriented' API (.NET) is pretty good and is where I focus my efforts nowadays.

I still have a lot to learn though - it's a very big topic...and then throw the ObjectARX/.NET API into the mix and you have even more to cover. If you're embarking on the MCSD route (I was doing this but life/work kept intruding), I wish you luck. Feel free to contact me via the boards or PM if you have questions.

Glenn R

  • Guest
Re: Open, Bind and Close
« Reply #24 on: August 20, 2008, 04:21:54 PM »
As an aside, if you were to combine what I posted above, with this, you would instantly have..........................a 'Batch in-memory Bind' program. However, I would strongly suggest, that you provide some sort of logging to file to indicate any failures that can then be rectified.

Maybe someone will take this idea and post the solution.

Cheers,
Glenn.

Spike Wilbury

  • Guest
Re: Open, Bind and Close
« Reply #25 on: August 20, 2008, 06:35:45 PM »
Thanks for the kind words Luis - I don't get out much ;)

I still remember seeing your lisp code back in the day (and still) and you are the master where that's concerned :)

He he.... and thanks too - but was master of disaster.

But I quit lisp, I use it but very very little on a daily basis.... I lost also the practice BTW :)


mcarson

  • Guest
Re: Open, Bind and Close
« Reply #26 on: August 21, 2008, 07:26:49 AM »
As an aside, if you were to combine what I posted above, with this, you would instantly have..........................a 'Batch in-memory Bind' program. However, I would strongly suggest, that you provide some sort of logging to file to indicate any failures that can then be rectified.

Maybe someone will take this idea and post the solution.

Cheers,
Glenn.

I think I will do this... a week maybe, given the other 'duties' I have to attend to.
Just to give something back...

Glenn R

  • Guest
Re: Open, Bind and Close
« Reply #27 on: August 21, 2008, 12:06:37 PM »

But I quit lisp, I use it but very very little on a daily basis.... I lost also the practice BTW :)


Pretty much the same for me too, Luis.

Glenn R

  • Guest
Re: Open, Bind and Close
« Reply #28 on: August 27, 2008, 12:42:55 PM »
mcarson,

Seeing as you seem to work with a lot of xrefs, you might be interested in Xref States.

Cheers,
Glenn.