This topic was briefly introduced almost a year ago, in this post. I then looked into the code a little further in a follow-up post. But at the time this topic wasn't the main thrust of the post, it was really more of an implementation detail.
So now it's time to do the topic a little more justice. :-)
Let's start with some terminology. What we're talking about today are often referred to as "side databases" or "external databases". Basically they're DWG files that are not open in the AutoCAD editor, but ones we want to access programmatically to load geometry or settings. You may also hear the term "lazy loaded" - these DWG files are not loaded completely into memory (unless you choose to access all the data stored in them), they are brought in, as needed, making the access very efficient.
Side databases have been available through ObjectARX since it was introduced in R13, but were introduced more recently in COM (the AxDb implementation was introduced several releases back, although I can't remember exactly when... perhaps it was in AutoCAD 2000 but it might have been later) and .NET (when we introduced the managed layer in 2005, I believe). One interesting point to note, is that any code you write using ObjectARX or .NET to access side databases can be used with almost no modification on top of RealDWG to access the same data outside AutoCAD. Although any code that's intermingled which accesses AutoCAD-resident functionality will not work, of course.
The basic technique is to create a Database object, and read a DWG file into it. Please remember to use the appropriate constructor: the standard constructor without arguments creates a Database object that cannot be used in this manner (it creates one that you would typically use to create a new DWG file). When reading a DWG you will need to pass False as the first argument - what you pass as the second depends on your need.
From there you work with the Database object, accessing the header variables and the objects stored in the various dictionaries and symbol tables, just as you would inside AutoCAD.
Let's take a very simple example, where we open a particular file on disk, and iterate through the model-space, listing a little bit of data about each object:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
namespace ExtractObjects
{
public class Commands
{
[CommandMethod("EOF")]
static public void ExtractObjectsFromFile()
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
// Ask the user to select a file
PromptResult res =
ed.GetString(
"\nEnter the path of a DWG or DXF file: "
);
if (res.Status == PromptStatus.OK)
{
// Create a database and try to load the file
Database db = new Database(false, true);
using (db)
{
try
{
db.ReadDwgFile(
res.StringResult,
System.IO.FileShare.Read,
false,
""
);
}
catch (System.Exception)
{
ed.WriteMessage(
"\nUnable to read drawing file."
);
return;
}
Transaction tr =
db.TransactionManager.StartTransaction();
using (tr)
{
// Open the blocktable, get the modelspace
BlockTable bt =
(BlockTable)tr.GetObject(
db.BlockTableId,
OpenMode.ForRead
);
BlockTableRecord btr =
(BlockTableRecord)tr.GetObject(
bt[BlockTableRecord.ModelSpace],
OpenMode.ForRead
);
// Iterate through it, dumping objects
foreach (ObjectId objId in btr)
{
Entity ent =
(Entity)tr.GetObject(
objId,
OpenMode.ForRead
);
// Let's get rid of the standard namespace
const string prefix =
"Autodesk.AutoCAD.DatabaseServices.";
string typeString =
ent.GetType().ToString();
if (typeString.Contains(prefix))
typeString =
typeString.Substring(prefix.Length);
ed.WriteMessage(
"\nEntity " +
ent.ObjectId.ToString() +
" of type " +
typeString +
" found on layer " +
ent.Layer +
" with colour " +
ent.Color.ToString()
);
}
}
}
}
}
}
}
Here's what happens when you run the code:
Command: EOF
Enter the path of a DWG or DXF file: "C:\Program Files\Autodesk\AutoCAD
2007\Sample\Sheet Sets\Architectural\S-03.dwg"
Entity (2127693096) of type Line found on layer Struc_Plan_GB_PL with colour
BYLAYER
Entity (2127693104) of type Line found on layer Struc_Plan_GB_PL with colour
BYLAYER
Entity (2127693112) of type Line found on layer Struc_Plan_GB_PL with colour
BYLAYER
Entity (2127693120) of type Line found on layer Struc_Plan_GB_PL with colour
BYLAYER
Entity (2127693128) of type Line found on layer Struc_Plan_GB_PL with colour
BYLAYER
Entity (2127693224) of type Line found on layer Struc_Plan_GB_PL with colour
BYLAYER
Entity (2127693232) of type Line found on layer Struc_Plan_GB_PL with colour
BYLAYER
Entity (2127693368) of type Line found on layer Struc_Plan_Ext with colour
BYLAYER
Entity (2127693376) of type Line found on layer Struc_Plan_Ext with colour
BYLAYER
Entity (2127693384) of type Line found on layer Struc_Plan_Ext with colour
BYLAYER
Entity (2127693392) of type Line found on layer Struc_Plan_Ext with colour
BYLAYER
Entity (2127693400) of type Line found on layer Struc_Plan_Ext with colour
BYLAYER
Entity (2127693408) of type Line found on layer Struc_Plan_Ext with colour
BYLAYER
Entity (2127693416) of type Line found on layer Struc_Plan_Ext with colour
BYLAYER
Entity (2127693424) of type Line found on layer Struc_Plan_Ext with colour
BYLAYER
Entity (2127695000) of type Line found on layer 2_Arch_Plan_Dim with colour
BYLAYER
Entity (2127695448) of type BlockReference found on layer 0 with colour BYLAYER
Entity (2127624240) of type BlockReference found on layer Building Section (2)
with colour BYLAYER
Entity (2127656048) of type BlockReference found on layer Structrual Base2 with
colour BYLAYER
Entity (2127656304) of type BlockReference found on layer grid plan with colour
BYLAYER
Entity (2127656560) of type BlockReference found on layer Stair 2 with colour
BYLAYER
I'm interested in looking at more complex scenarios where people might need to access side databases from their code. Please post any suggestions you might have as a comment (or just drop me an email).

Subscribe via RSS
Thank you Kean for the theme,
One of the frequent problems is to check all (or some) dwg files in a folder. It is necessary to detect a valid dwg version, to check for some specific entities (present or absent), to add some objects (e.g. format box) and to publish (or to plot).
Posted by: Nikolay Poleshchuk | July 19, 2007 at 05:00 AM
Hi Nikolay,
Thanks - this is great input.
I'll try to cover the batch-processing aspect (going through files in a folder, checking their versions, and then reading/performing some operation), but printing/plotting can only happen on editor-resident drawings.
AutoCAD currently needs the graphics pipeline to generate printed graphics, and this is not present for side databases. So this is certainly something interesting to cover, but would be more about batching inside the editor than using side databases.
Regards,
Kean
Posted by: Kean | July 19, 2007 at 12:50 PM
Hi Kean!
Excellent example! From an academic stand-point, what would really make this appliction "shine" is replacing the command line prompt with a Windows Form.
Regards,
Nick
Posted by: Nick Schuckert | July 19, 2007 at 01:53 PM
Hi Kean
Great topic. I would be interested in opening drawing database and change attribute text in a blockrefrence. Save and close in the end.
Cheers
Tore
Posted by: Tore | July 19, 2007 at 02:31 PM
Kean,
If plotting is impossible in an invisible mode then let us save modified dwg file to a subfolder "Ready for plotting".
Posted by: Nikolay Poleshchuk | July 20, 2007 at 04:50 AM
Good example.But I want to know if I can access the entities in a drawing without start the AutoCAD.Maybe this is a DBX topic,but I know nothing about DBX,where I can find some helpful articles like here?You know I take here as my ObjectARX classroom:),Do you know some other blogs talk about ObjectDBX ?Thank you.
Posted by: Travor | July 20, 2007 at 10:41 AM
Travor -
I'm not sure if you're aware, but RealDWG is the new name for ObjectDBX (and I did mention RealDWG in the above article, albeit briefly).
The above code will work with very little modification in RealDWG, and I'll add it to my list to do a specific article on RealDWG at some point.
Regards,
Kean
Posted by: Kean | July 20, 2007 at 11:13 AM
Hi Kean.
Thank you for your mention.It seems I should get something about RealDWG.I am looking forward to your RealDWG articles.Many thanks.
Posted by: Travor | July 21, 2007 at 03:46 PM
Hi Kean,
I've really enjoyed reading your articles. This is the best resource I have found for AutoCAD .NET programming. Thank you.
I am working (or about to start) on creating a program that goes through the dwg files in a directory and purges each drawing. Don't ask why one would want to do this as it is not for me :), but it what I'm interested in and it kind of ties in with the first poster's desire to iterate through a list of drawings.
Thanks again.
Posted by: Kyle Wecker | July 27, 2007 at 07:14 AM
Just read your latest post. It seems you have already done this. While here though, is it possible to do what I asked using the PurgeAll() command? (I haven't experimented yet, and I'm being lazy). Thanks again.
Posted by: Kyle Wecker | July 27, 2007 at 07:20 AM
Hi Kyle,
You could fire off the -PURGE ALL command (sending the command to the commandline - this would mean the drawing had to be loaded in the AutoCAD editor, mind) or you could create a list of all the objects (blocks, layers, linetypes, etc.) and pass that list through to db.Purge(). This would remove any objects that should not be purged. The remaining object IDs in the list can be used to open and erase the purgable objects in the drawing.
I'll add this to my list to tackle, at some point.
Regards,
Kean
Posted by: Kean | July 27, 2007 at 09:53 AM
That's great information Kean. I am interested in how it can be accomplished through the C++ code/Arx. What about doing this with system variables such as dimtxt, dimscale etc?
Here is my problem scenario. I have a block in drawing A1.dwg, and now I want to insert A1.dwg block into another drawing A2.dwg. I am trying to get the dimtxt value for A1.dwg before the insertion process so that I can perhaps set the current drawings dimtxt attribute to the one from A1.dwg. I know it's quite simple for current drawings, but what about other drawings remotely.
So to sum it up, the function should be able to read dimtxt system variable from a drawing that is not open and return the dimtxt value for that drawing.
Vector
Posted by: vector | August 10, 2007 at 09:10 AM
I think the possible solution to this problem would be to use ObjectDBX. However, as per my information there is no way to access system variables from another drawing that is not open in an AutoCAD session through ObjectDBX. Not even GetVariable and SetVariable, since GetVariable and SetVariable are methods of AcadDocument,
they only work on AcadDocuments (they're just wrappers for the ObjectARX counterpart of the (getvar) and (setvar) LISP
functions). So there's no method for getting/setting system variables stored in drawings that are accessed directly via
ObjectDBX.
Could you please confirm on this?
Thanks,
vector
Posted by: vector | August 10, 2007 at 01:03 PM
Vector -
As long as you have a pointer to the Database (or AcDbDatabase) then you can access the "Dimtxt" property - db.Dimtxt (or use the AcDbDatabase::dimtxt() function).
This is true whether inside AutoCAD or using RealDWG (the new name for ObjectDBX).
Regards,
Kean
Posted by: Kean | August 10, 2007 at 01:43 PM
Kean:
Do you know what signature would work? I can't find the Object Model documentation anywhere :
Suppose I do this
AcDbDatabase pDb( Adesk::kFalse );
pDb.dimtxt(dimtxtVal, DwgName);
is this the right signature?
Where DwgName is the drawing name whose dimtxt I want
Thanks,
Vector
Posted by: vector | August 10, 2007 at 02:17 PM
Vector -
You need to use readDwgFile() to read your DWG into the AcDbDatabase before accessing the dimTxt() method using:
double dt = db.dimtxt();
You'll find the documentation on the ObjectARX SDK under the docs folder.
It seems as though you're new to using ObjectARX. Are you sure you want to stick with C++, rather than using .NET? (Even without substantial documentation I find AutoCAD .NET coding easier and the object model much more discoverable).
A word of caution... I'd recommend against developing anything in ObjectARX (C++) unless you've worked through the Labs (in the "arxlabs" folder) or attended introductory training provided by my team. It will really save you a lot of thrashing.
Regards,
Kean
Posted by: Kean | August 10, 2007 at 02:57 PM
Kean,
How to access the ACADMap ObjectData Tables, without opening the dwg in ACAD Editor.
Senthil
Posted by: Senthil | December 21, 2007 at 06:43 AM
Sorry, Senthil - I don't know the Map 3D APIs and am unlikely to address this topic on this blog.
You should submit your question via one of the discussion groups or the ADN website (if you're a member).
Kean
Posted by: Kean | December 21, 2007 at 09:50 AM
hi kean
this is satheesh from india.i'm currently assined wth an autocad automation project where i hv to draw in autocad from .net environment.i'm using managed dlls with c# as my programming language .
i'm currently stuck in a sitaution where i hv to do fillet command to join two lines.for ur knowledge i 'm just a beginner who hv just started learning about autocad.net programming.u might feel this is a simple doubt,but it wud be a great help for me.
thanx
Posted by: satheesh | March 10, 2008 at 01:05 PM
Satheesh -
Please post your question to the AutoCAD .NET Discussion Group, or submit it via ADN, if you're a member.
Regards,
Kean
Posted by: Kean | March 10, 2008 at 01:55 PM
hi
please,
Im after openning file dwg closed autocad .
im guide please
bye
Posted by: rezaei | July 09, 2008 at 09:18 AM
Sorry - I don't understand, but it doesn't seem related to the code in this post. Please submit your question to one of the discussion groups.
Kean
Posted by: Kean | July 09, 2008 at 09:35 AM
I get a eBadDwgHeader exception when trying to open dxf files. Is it possible to open dxf files with db.ReadDwgFile() or is there another way to open/import them using RealDWG?
Posted by: Mattias | September 11, 2008 at 02:54 PM
You can use RealDwgFile(). It's probably a problem with the DXF file, or with the Database constructor.
Make sure you don't use the default constructor (Database db = new Database();).
For R13-R2009 DWG files use:
Database db = new Database(false, ...);
For earlier DWGs use:
Database db = new Database(true, ...);
Kean
Posted by: Kean | September 11, 2008 at 03:07 PM
I have tried different Database constructors but DXF files still give eBadDwgHeader exceptions, even with your EOF example. DWG files works fine.
I'm using RealDWG 2009 and have added
acdbmgd.dll and acmgd.dll to the projects references. All my dxf files can be opened correctly in autocad.
Regards,
Mattias
Posted by: Mattias | September 12, 2008 at 09:44 AM