Import blocks from an external DWG file using .NET

We're going to use a "side database" - a drawing that is loaded in memory, but not into the AutoCAD editor - to import the blocks from another drawing into the one active in the editor.

Here's some C# code. The inline comments describe what is being done along the way. Incidentally, the code could very easily be converted into a RealDWG application that works outside of AutoCAD (we would simply need to change the destDb from the MdiActiveDocument's Database to the HostApplicationServices' WorkingDatabase, and use a different user interface for getting/presenting strings from/to the user).

using System;

using Autodesk.AutoCAD;

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.Geometry;

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using System.Collections.Generic;

namespace BlockImport

{

  public class BlockImportClass

  {

    [CommandMethod("IB")]

    public void ImportBlocks()

    {

      DocumentCollection dm =

          Application.DocumentManager;

      Editor ed = dm.MdiActiveDocument.Editor;

      Database destDb = dm.MdiActiveDocument.Database;

      Database sourceDb = new Database(false, true);

      PromptResult sourceFileName;

      try

      {

        // Get name of DWG from which to copy blocks

        sourceFileName =

          ed.GetString("\nEnter the name of the source drawing: ");

        // Read the DWG into a side database

        sourceDb.ReadDwgFile(sourceFileName.StringResult,

                            System.IO.FileShare.Read,

                            true,

                            "");

        // Create a variable to store the list of block identifiers

        ObjectIdCollection blockIds = new ObjectIdCollection();

        Autodesk.AutoCAD.DatabaseServices.TransactionManager tm =

          sourceDb.TransactionManager;

        using (Transaction myT = tm.StartTransaction())

        {

          // Open the block table

          BlockTable bt =

              (BlockTable)tm.GetObject(sourceDb.BlockTableId,

                                      OpenMode.ForRead,

                                      false);

          // Check each block in the block table

          foreach (ObjectId btrId in bt)

          {

            BlockTableRecord btr =

              (BlockTableRecord)tm.GetObject(btrId,

                                            OpenMode.ForRead,

                                            false);

            // Only add named & non-layout blocks to the copy list

            if (!btr.IsAnonymous && !btr.IsLayout)

              blockIds.Add(btrId);

            btr.Dispose();

          }

        }

        // Copy blocks from source to destination database

        IdMapping mapping = new IdMapping();

        sourceDb.WblockCloneObjects(blockIds,

                                    destDb.BlockTableId,

                                    mapping,

                                    DuplicateRecordCloning.Replace,

                                    false);

        ed.WriteMessage("\nCopied "

                        + blockIds.Count.ToString()

                        + " block definitions from "

                        + sourceFileName.StringResult

                        + " to the current drawing.");

      }

      catch(Autodesk.AutoCAD.Runtime.Exception ex)

      {

          ed.WriteMessage("\nError during copy: " + ex.Message);

      }

      sourceDb.Dispose();

    }

  }

}

And that's all there is to it. More information on the various objects/properties/methods used can be found in the ObjectARX Reference.

2 responses to “Import blocks from an external DWG file using .NET”

  1. With this update/override any existing blocks in the active dwg? If not how would you do so?

  2. Hi Barry,

    Yes - the key is in the 4th argument to WblockCloneObject(), which is DuplicateRecordCloning.Replace. If you don't want to overwrite/update existing blocks you can use DuplicateRecordCloning.Ignore.

    I'll post another entry next week to look into the code in a bit more detail - it was getting late on Friday night and I wanted to get the code posted before the weekend. There are a few details that are worth looking at a little closer.

    Kean

  3. Kean,

    I have found your blog to be very helpful. I was hoping to meet you at AU2006 but didn't have time to find everyone. Don't even know if you were there.

    Do you know if there is a way to copy a block that has sub blocks and create new blocks and sub blocks without the original blocks xdata? I'm trying to create a "dumb" copy of the original block without all the xdata to use in various other views.

  4. Hi Stuart,

    I wasn't able to make it to this year's AU, unfortunately. Perhaps next year.

    The way to go should be to go through the "mapping" object populated by WblockCloneObjects(), and post-process the various new blocks to dumb them down (removing their xdata).

    Regards,

    Kean

  5. Stefano Benedetti Avatar
    Stefano Benedetti

    Hi,

    I'm using this code in my application but I need to import also dynamic properties. How can I do it?
    Thanks

  6. Do you mean dynamic blocks? Please explain exactly what doesn't work in the code, and I'll take a look. I don't remember whether I tested this with dynamic blocks (I posted it quite some time ago).

    Kean

  7. Stefano Benedetti Avatar
    Stefano Benedetti

    Hi Kean. Yes I mean dynamic block.
    I have a dwg (Dest.dwg) with a static block called PB.
    I want to import a block called PB from an external file (Library.dwg).
    When I run "IB" command block in Dest.dwg the PB block is modified but it doesn't have rotation, visibility and other dynamic actions.
    Thanks

  8. Hi Stefano,

    I tested the IB command with one of the standard Dynamic Block libraries (in "C:\Program Files\Autodesk\AutoCAD 2008\Sample\Dynamic Blocks\Annotation - Metric.dwg" on my system), and it seemed to work fine. I could insert the imported Dynamic Blocks and they appeared to behave in a dynamic fashion. Can you test against the standard ones, and try to narrow down the specific problem?

    Regards,

    Kean

  9. Stefano Benedetti Avatar

    I post this comment to notify readers that Kean and I understand that the problem with dynamic block resides in AutoCAD 2006. In AutoCAD 2008 it's possibile to redefine a block also with dynamic property. Thanks Kean!

  10. Kean,
    Thanks for this sample code. I've tried several different similar methods in VB.Net but it always ended with a fatal error. If you don't mind I would like to explain how I entend to use the code to see if you have a better suggestion. I have hundreds of Annotation blocks that I use for both imperial and metric drawings. I'm sure you're aware that if the block being inserted is an annotative block the insunits are ignored. I need to insert the blocks and scale them by both the annotative scale and the insunits. I would also like to put these blocks on toolpalletes. I've written the code to scale the blocks with both parameters and it works great. The only problem is I wrote in VB.Net. My skills are pretty limited with C#. My plan was to code the command macro on the toolpallete to set the UserS1 variable to the path of the source drawing and UserS2 to the name of the block. Then I would call the command to import and scale the block. I was able to tweak your code to read these variables and import the block. Now all I need to do is convert my VB.Net code to C# so I can insert the block. Could you possible give me a similar example of your C# code in VB? Or if you have any other suggestions I would really like to hear them.

    Thanks,
    Steve

  11. Steve,

    I'm sorry for the delay in responding. When converting between C# and VB, I usually use the tool I linked to by this post:

    keanw.com/2006/08/some_cool_copyp.html

    You can also use the online conversions tools directly that this AddIn connects to:

    carlosag.net/Tools/CodeTranslator
    kamalpatel.net/ConvertCSharp2VB.aspx

    Also, apparently SharpDevelop is a good tool for code conversion.

    Regards,

    Kean

  12. Is there a similar way for creating Block Definitions 'on the fly'? I need to go from a polyline entity to a block definition...

  13. Yes, you can certainly add a new BlockTableRecord to the BlockTable and use its ID as the destination for the WblockCloneObjects() call (passing in the ObjectIds of the objects to put in the block).

    Kean

  14. Am I mistaken or is this the .NET equivalent to the following line of VBA code:

    ThisDrawing.ModelSpace.InsertBlock(newCoord, "c:\blockName.dwg", xyzScale, xyzScale, xyzScale, 0)

    I'm confused by the amount of code needed to do what was done in VBA with 1 line. Am I missing something?

  15. Well, yes and no... InsertBlock() loads the DWG into a BlockTableRecord and inserts it into the space upon which it's called. The above code imports blocks from a DWG file so they can be inserted at the user's leisure.

    The COM API (to which VBA provides access) is higher-level than .NET - it's focus is automating tasks, while .NET (and ObjectARX, upon which it is very closely based) are more powerful APIs, yet sometimes require more code to do certain tasks.

    It's ultimately a balance between control and succinctness: with lower-level code you get much greater control but it often comes with a coding overhead.

    Kean

  16. Omar Martínez Avatar
    Omar Martínez

    Hi Kean,

    We have had advances in our project thanks to your blog. But now, we have found another problem. We have been able to import blocks and layer from a DWG to another, but we haven't been able to import the entities. Our project consist in import completly dwg into another dwg. Do you know if that is possible?
    With the objectARX can add new entities in a blockTableRecord, but can we do that from another dwg?

    Thanks,

    Omar

  17. Kean Walmsley Avatar

    Hi Omar,

    WblockCloneObjects() and Insert() should get you there.

    Please submit follow-up questions via ADN, if you're a member, or the Autodesk discussion groups, if not.

    Regards,

    Kean

  18. Hi Kean,

    What if the there is already a blocktablerecord in the destination database with the same name of the blocktablerecord we are trying to copy?
    I tried to change the name of the source blocktablerecord with "btr.name = newBlockName" , but then I got a eAlreadyInDb exception.

    Thanks,
    Kostas

  19. Hi Kostas,

    It's the "DuplicateRecordCloning.Replace" argument that is telling AutoCAD how to handle this. You can change that to hopefully provide the behaviour you're looking for.

    Regards,

    Kean

  20. Dear Kean:
    How are you i hope evry thing is oky,
    I try to use this code in a toolpalette in autocad 2010 but i got this error (Error during copy : eLockViolation),
    I need your help.
    thanks.

  21. Kean Walmsley Avatar
    Kean Walmsley

    Dear Abdo,

    I'm well, thanks.

    Try launching the command from your modeless UI using Document.SendStringToExecute(). Otherwise you have to jump through hoops to lock the current document, etc. - it's better to let AutoCAD's command mechanism to handle all that implicitly.

    Regards,

    Kean

  22. Hi Kean,
    I want to create individual drawing files from all the blockreferences found in a drawing file, how can i achieve this?

  23. Kean Walmsley Avatar

    Hi Santosh,

    This isn't a forum for support.

    Your comment doesn't appear to relate directly to this post, so please submit your question to the ADN team, if you're a member, or otherwise the AutoCAD .NET Discussion Group.

    Regards,

    Kean

  24. Hi!

    It's a excellent post.

    Could I change the layer on the target database?

    Thanks

  25. Kean Walmsley Avatar

    If you iterate through the "mapping" variable you will be able to open and modify the resulting objects.

    Kean

  26. I could not get the .SendStringToExicute to work properly. It held that command until the end of my process. I need it to do this operation during the middle of it since I am inserting the blocks too. So the following is what I came up with for locking the document. After you locked and unlocked it, you had to make sure that the destDoc was the active one.

    Public Function CloneBlock(ByVal mBlockItem As BlockItem) As Boolean
    Dim CloneMe As Boolean = True
    If ThisDrawingHasBlock(mBlockItem.Name) Then
    If Not mBlockItem.OverRite Then CloneMe = False
    End If

    If CloneMe Then
    Dim dm As DocumentCollection = Application.DocumentManager
    Dim ed As Editor = dm.MdiActiveDocument.Editor
    Dim DestDoc As Document = dm.MdiActiveDocument
    Dim DestDb As Database = DestDoc.Database
    Dim sourceDb As New Database(False, True)
    Dim ResultMsg As String = ""
    Try
    ' Read the DWG into a side database
    sourceDb.ReadDwgFile(mBlockItem.FileName, System.IO.FileShare.Read, True, "")
    ' Create a variable to store the list of block identifiers
    Dim blockIds As New ObjectIdCollection()
    Dim tm As Autodesk.AutoCAD.DatabaseServices.TransactionManager = sourceDb.TransactionManager
    Using myT As Transaction = tm.StartTransaction()
    ' Open the block table
    Dim bt As BlockTable = DirectCast(tm.GetObject(sourceDb.BlockTableId, OpenMode.ForRead, False), BlockTable)
    ' Check each block in the block table
    blockIds.Add(FindMyBlockID(mBlockItem.Name, bt, tm))
    End Using

    ' Copy blocks from source to destination database
    If blockIds.Count > 0 Then
    Dim mapping As New IdMapping()
    Using DestLock As DocumentLock = DestDoc.LockDocument
    sourceDb.WblockCloneObjects(blockIds, DestDb.BlockTableId, mapping, DuplicateRecordCloning.Replace, False)
    End Using
    End If
    ResultMsg = vbLf & "Copied block definitions from " + mBlockItem.FileName + " to the current drawing."
    Catch ex As Autodesk.AutoCAD.Runtime.Exception
    ResultMsg = vbLf & "Error during copy: " + ex.Message
    End Try
    sourceDb.Dispose()
    '' Set the new document current (very important)
    dm.MdiActiveDocument = DestDoc
    ed.WriteMessage(ResultMsg)
    Return True
    End If

    Return False
    End Function

    Private Function FindMyBlockID(ByVal BlockName As String, ByRef aBlockTable As BlockTable, ByVal Trans As Autodesk.AutoCAD.DatabaseServices.TransactionManager) As ObjectId
    For Each btrId As ObjectId In aBlockTable
    Dim btr As BlockTableRecord = DirectCast(Trans.GetObject(btrId, OpenMode.ForRead, False), BlockTableRecord)
    ' Only add named & non-layout blocks to the copy list
    If Not btr.IsAnonymous AndAlso Not btr.IsLayout Then
    If btr.Name = BlockName Then
    Dim ObjID As ObjectId = btr.ObjectId
    btr.Dispose()
    Return ObjID
    End If
    End If
    btr.Dispose()
    Next
    Return Nothing
    End Function

  27. Hi Kean,
    In autocad 2007 ReadDwgFile fails while read 2000 version dwg file, but works to read 2004 files, What can I do?

  28. There's no reason I'm aware of that AutoCAD 2007 would not read 2000 DWGs (it should read drawings going back to version 2, if I recall correctly).

    This is most probably due to an issue with a specific drawing.

    Kean

  29. thanks, Mr Walmsley, Is there a way to decide what type of version dwgfile while using the ReadDwgFile method?

    how can I convert the dwg file version silently without open it in the document interface?

    your sincerely ,Qu

  30. The first six bytes of the DWG file will tell you:

    keanw.com/2006/08/breaking_it_dow.html

    and

    keanw.com/2010/10/sortonversion-scriptpro.html

    For follow-on questions, please post to ADN or to the online discussion groups.

    Regards,

    Kean

  31. Hi Kean,
    The online Autocad .NET Developers Guide it says about document locking: "You want to lock the document when your application: ... Accesses a loaded document other than the current document ..."

    Question: Should the documents in your (this) example of accessing "a loaded document other than the current document" not be locked? Sorry, if I overlooked something here.
    Thx, Stephan

  32. Hi Stephan,

    No need, in this case. We're not accessing Databases (DWGs) related to other "Documents" (i.e. that are loaded in the editor), we're reading drawings into Databases - with nothing to do with Documents - using ReadDwgFile() and cloning the BlockTable contents into the Database associated with the current Document (which is locked automatically by the command).

    Regards,

    Kean

  33. I understand now. Thank you for the explaination.

  34. hi...

    How to insert block into autocad drawing using object arx in dot net....
    RAKESH SHINDE
    PUNE

  35. Rakesh,

    According to the "three strikes" rule I've just decided to introduce and enforce on people posting support requests as comments on my blog, the next time you post such a request, I will block you from commenting.

    This may seem harsh, but you're clearly ignoring my (so far polite) requests, and this is really starting to waste my time.

    Regards,

    Kean

  36. I also tried with dynamic blocks and it doesn't work. as Name I get something like *U10 and ist is set to anonymous so the block is not added at

    // Only add named & non-layout blocks to the copy list
    if (!btr.IsAnonymous && !btr.IsLayout)
    blockIds.Add(btrId);

    I'm new to Autocad and programming Autocad. Is it possible that the content dwg-file must be edited to work? In VBA there were no problems.

  37. It should work with dynamic blocks (although not with older versions of AutoCAD - looking back at the comments things worked well from AutoCAD 2008 onwards, at the very least).

    Kean

  38. Hello mr Walmsley,

    first of all, thank you for your blogs. They are very helpfull.

    I use your code above (exactly the same) to redefine a dynamic block. It's a simple block for testing, a square with a hatch and a stretch parameter. Both the source-drawing and the current drawing have been audited.

    After I run the command, the anonymous blocks (for the dynamic block references with non-default dynamic properties) do not get updated. Is there a way to achieve this, or is that off-topic for this blog?
    I tried to code it myself, by storing all dynamic property values, resetting all block references and then setting the dynamic property values again, but I'm really hoping for a more efficient way.

    My second problem is, that if I run the AUDIT command after this command, I get some errors:

    auditedAcDbBlockLinearParameter(1CE) was not
    repaired.
    AcDbBlockLinearGrip(1CF) was not repaired.
    AcDbBlockGripExpr(1D0) was not repaired.
    AcDbBlockGripExpr(1D1) was not repaired.
    AcDbBlockStretchAction(1D2) was not repaired.

    They clearly are related to dynamic blocks. Have you ANY idea what may cause them?

    I tried the code on 2 different systems, both running AutoCAD2009.

    Thank you for your time,

    Erik.

    1. Erik, Did you ever find a solution to this problem? I'm having the same issue with audit errors after using WblockCloneObjects and then UpdateAnonymousBlocks() DIMREGEN doesn't seem to help with the issue at all.

  39. Hi Erik,

    Maybe it's to do with the "dynamic" block table record (BTR) not being imported. Some information in this post may help:

    keanw.com/2009/03/painting-properties-between-dynamic-autocad-blocks-using-net.html

    Perhaps it's worth adjusting the code to go from the BTR back to a BlockReference (using GetBlockReferenceIds()) and getting the dynamic BTR using br.DynamicBlockTableRecord() to add to the blockIds collection.

    But that's just guessing - it's been a while since I looked at this.

    In case this doesn't help, I suggest posting a complete description on the AutoCAD .NET Discussion Group (including code and a DWG). Someone there should be able to help.

    Regards,

    Kean

  40. Hello mr Walmsley,

    the AutoCAD .NET Discussion Group has been helpfull, but could not help me with this problem.

    I found out that inserting a dynamic block from another drawing with AutoCAD's design center also causes audit errors. So for now I am assuming it is not possible without the audit errors, on my configurations at least (CAD version, OS, hardware, etc.). I don't know if it is true for other configurations.

    As for updating the anonymous blocks, it turns out there is a function 'BlockTableRecord.UpdateAnonymousBlocks()'.

    Thought I'd post this info here,

    Again, thanks for the blogs!

  41. executing the command 'DIMREGEN' will fix your audit errors.

  42. executing the command 'DIMREGEN' will fix your audit errors.

  43. Andre Dagenais Avatar
    Andre Dagenais

    Hi Kean,

    I used your code (translate in VB .Net) for many projects and it works very well. But I try it with AutoCAD 2012 and I have a bug. After the blocks are imported, I insert it programmatically (I use another solution for it from your blog, thank you so much) and it is also working well. But if I try to insert the same block with the Insert command I have the message, "The block have changed. Would you like to redefine it?" If I say yes, the block inserted is empty. If I say no, the block is working well and the message won't be show again. I don't have this problem with 2010 or 2011. I try with code compile with VS2008 and VS2010(using AutoCAD 2012 reference). I'm also working with 64 bits release (Windows 7).

    I have no clue about this problem.

    Thank you very much,

    Regards,

    Andre

  44. Andre Dagenais Avatar
    Andre Dagenais

    Hi Kean,

    I apologize, it is working well in AutoCAD 2012. I found the culprit. It was an Autolisp routine running at startup. This routine use an old technique to insert dimstyle, it insert a whole drawing. This way, all the dimstyle, layers and blocks and so on, are imported in the current drawing. And a conflict appears. I don't know what exactly but I will revise the way to import DIMSTYLE.

    Regards,

    Andre

  45. Kean Walmsley Avatar

    Hi Andre,

    Glad to hear you've found the cause.

    Regards,

    Kean

  46. Hi Kean,
    I'm just a new bie to AutoCAD.net programming, in fact, to AutoCAD as well :).

    I've posted my problem here:
    forums.autodesk.com/t5/NET/Drag-and-Drop-dwg-files-from-my-ListBox-hosted-in-Palettset/td-p/3521362

    and in relation to that I'm learning to achieve my target.

    Your code is working fine and I've observed its working while using Arx Inspector. But one thing, I'm not able to understand.

    Whenever I import Blocks from any dwg, they come in database, but doesn't display in the AutoCAD drawing area.

    Do I have to inform and commit Transaction Manager for this purpose?

    Kindly read my question on Discussion forum and help me to understand achieve this target.

    Best regards

  47. Kean Walmsley Avatar

    I unfortunately don't have time to spend on this, right now... did Art's response help? Hopefully - if not - someone else will be able to give you some guidance.

    Kean

  48. Hi Kean,
    Thanks for your reply.
    Yes, I got it on next day, when I posted on your blog. Here is the link:
    forums.autodesk.com/t5/NET/c-block-insert/m-p/1744539#M4520

    Few more call using Transaction manager and we have the blocks on drawing area.

    Thanks for your blog posts. They are really helpful.. 🙂

  49. Hi Kean,
    I have a similar code for importing blocks using ReadDwgFile method. That was working perfectly (in a custom app for ACAD2010) until yesterday that I was trying to migrate my application to ACAD 2012. Then I realized a significant performance hit (very slow) on the import method and the bottle-neck seems to be ReadDwgFile. I use a 64bit machine. Are you aware of any issues running that method in AutoCAD 2012 (specially 64bit).
    Thanks,

  50. I just tested your code in AutoCAD2012 (VS2010) and on a new drawing it took about 12sec to finish. Is that normal?

  51. Hi Hoss,

    There shouldn't be a slow-down when upgrading from 2010 to 2012. It could be slow if your system is missing RAM or the DWG file being imported is large, but the code itself isn't doing anything very special.

    Does AutoCAD 2012 seem sluggish in general to you on this system when compared with 2010?

    Regards,

    Kean

  52. Hi,
    This example works as expected if one is working with Acad.DocumentManager.MdiActiveDocument but works a little differently with a newly created document (using Application.DocumentManager.Add("acad.dwt")). When using a newly created document, the drawing gets inserted into paper space instead of into model space, why does that happen?

    Thanks

  53. I'm confused: this code just copies across block definitions - it doesn't create anything in either model- or paperspace.

    Are you referring to another post, or have you added some logic to your app that isn't reflected in the above code?

    Kean

  54. Hi kean, I want to import a shape file into dwg, how can i do it? when i use below code :
    importer.Init("SHP",d:\\files\\CAD\\test.shp" );
    importer.SaveImportFormat(files[i]);
    importer.Import(true);

    autocad process 0 object and insert no object
    my shape file is ok i've tested.
    can u help me what to do?
    thank u in advance

  55. *(Corrected)
    Hi kean, I want to import a shape file into dwg, how can i do it? when i use below code :
    importer.Init("SHP","d:\\files\\CAD\\test.shp" );
    importer.Import(true);

    autocad process 0 object and insert no object
    my shape file is ok i've tested.
    can u help me what to do?
    thank u in advance

  56. What kind of .SHP are we talking about: an AutoCAD Shape file or an ESRI ShapeFile?

    And I'm not familiar with the importer object you're using: what type is it and where are you getting it from?

    Kean

  57. hi kean this is my code
    using map = Autodesk.Gis.Map;
    ...
    map.ImportExport.Importer importer = map.HostMapApplicationServices.Application.Importer;
    importer.Init("SHP", "d:\\file\\CAD\\ISELFCT.shp");
    importer.LoadImportFormat("d:\\files\\CAD\\Imp_Attr.epf");//
    importer.Import();

    in fact i want to import shapefile (esri exported shape file) into dwg in autocad, like mapimport command, after executing mapimport a file dialogue is opened to select shapefiles, I want to access the selected files in dialogue, but i couldn't, so i desided to write my own import function using code above, i searched alot in web, but cou;n't solve the problem yet
    thanx again for ur helpful blog

  58. Hi Mehrsa,

    Thanks for clarifying.

    This is Map 3D functionality, so it's really not my area, I'm afraid.

    You might try the Infrastructure Modeling ADN DevBlog, in case that has the information you need, or post a question to the appropriate online discussion forum (the one for "Map 3D Developers", probably).

    Regards,

    Kean

  59. Hello Kean,

    I have a situation, where it is necessary to use "manglename" as option for duplicaterecordcloning. I use the wblockcloneobjects method to "copy/paste" dynamic blocks between databases, where the names are out of interest. So I can achieve a huge gain on performace. BUT, manglename also mangles the layer-names, wich is in this scenario an unwanted sideeffect. Is there a possibility that mangeling is apllied to Blocktablerecords only?
    I only can think of backing up the layernames of the objects in the tempfile (as generated by copyclip), set them all to layer "0" and after the insert I set them back to their Layer in the destination database (most Layer will exist in destination.
    Since this means at least 3 extra loops, I may avoid it concerning loss of performance.
    Thanks in advance,
    Daniel

  60. Kean Walmsley Avatar

    Hi Daniel,

    I don't think there's a selective way to do this, although perhaps not mangling and then renaming the BTRs would work (not sure whether you'd see the performance gains you've achieved, though).

    But it's been a while since I've spent much time on cloning... I suggest posting your question to the AutoCAD .NET discussion group or to the ADN team.

    Regards,

    Kean

  61. Hello Kean, thanks for the answer. Sorry for reacting that late... Thought I get a Mail notification from the system 🙂

    I'll check on the sources you mentioned.
    Regards,
    Daniel

  62. Hi Kean,

    I use above code to add xref layer to current drawing. when i do need the imported xref layer i set it to isoff = true but when i use the Autodesk.GIS.Map.ImportExport.Exporter method it also import said layer even though it is invisible to the current drawing. How do use the method Autodesk.GIS.Map.ImportExport.Exporter on selected layers only?

  63. Hi Sherwin,

    Sorry - you'll have to ask the ADN team or post on the discussion groups: I don't know anything about the Map 3D API layer.

    Regards,

    Kean

  64. Hi Kean.

    Congratulations on all the stuff you publish. This code worked well with several DWG input files, except those generated with WBLOCK command. When I open these files, AutoCAD displays a message like this:

    "<file> contains elements of authoring. Open in Block Editor?".

    For these files the loop in the code below does not find the block definitions contained in the file.

    // Check each block in the block table
    foreach (ObjectId btrId in bt)

    What happens?
    Thanks

  65. Hi Márcio,

    If I understand correctly, you're talking about block definitions that have been wblocked as separate drawings. Which means their contents get placed directly in modelspace.

    You could certainly change the logic to bring the contents of the modelspace into a block definition, but it would add some complexity.

    Regards,

    Kean

  66. It's possible to do it from COM interop?

    1. Not sure... you might be able to use the INSERT command to do something, but COM doesn't give you low-level DWG access. You could always implement the code in .NET and call it from COM, of course.

      Kean

      1. Thanks Kean for your fast answer.

        I didn't found an way to do it from COM so I did by .NET and call from COM.

        But what i needed was read attributes of a block from other dwg to populate one winform, and I had to insert at drawing, read attributes and delete it.

        But anyway, thanks again!

  67. Hi,

    Is it possible to WBlockCloneObject "Styles"?

    1. Anything that's database-resident should be clonable via this mechanism, including styles.

      Kean

  68. Kean,

    Can I import specific block from other drawing not all blocks?

    1. Pankaj,

      Of course: just put the ObjectId of the block you want (and no others) in the blockIds variable.

      Regards,

      Kean

      1. Thanks Kean, for quick reply.
        Also , I am new to autocad API, I did quite some programming and app development in .net.
        Can you suggest where I can start?
        Can you suggest any book?

          1. Thanks kean, that's very useful

  69. Hello Kean,

    I was using above code to import blocks, when I run code it says total number of block definitions imported etc. but I can not see anything on drawing!! Can you please explain?

    1. Try using the INSERT command and seeing the blocks that have been added to the drop-down.

      Kean

      1. Thanks Kean for quick reply.
        I was wondering about creating drawing from template drawing which has all blocks. So steps shall be use above code to import specific blocks but how can I place them inside drawing using .net code itself?

        1. You need to create BlockReference objects for the various BlockTableRecords and add them to the modelspace.

          Kean

  70. Hello Kean,
    I have added xrecords in the blockreference in source file. (reason is each block has different value for each xrecords). Now I need to copy/clone specified blockreference from the source file to destination file. I used

    ObjectIdCollection ids = new ObjectIdCollection();
    BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt["block_name"]
    , OpenMode.ForRead);
    ObjectIdCollection blockRefIds = btr.GetBlockReferenceIds(true, true);
    BlockReference br = (BlockReference)tr.GetObject(blockRefIds[0], OpenMode.ForRead);
    ids.Add(br.Id);
    Database destdb = doc.Database;
    IdMapping iMap = new IdMapping();
    destdb.WblockCloneObjects(ids, destdb.BlockTableId
    , iMap, DuplicateRecordCloning.Replace, false);

    Now I use 'Insert' command to place blockreference, but it does not carry xrecords

    please help.

    1. Hi Pushkar,

      Please post your support questions to the AutoCAD .NET Discussion Group.

      Many thanks,

      Kean

  71. Hi Kean/All,

    Had a issue with this code crashing AutoCAD. It worked fine the first time I tested, so I implemented it then it never worked again. The particular crash only occurred after the program finished running so debugging was a pain. The error was:

    An unhandled exception of type 'System.AccessViolationException' occurred in AcdbMgd.dll

    I think I narrowed it down to something with automatic garbage collection that was messing up and causing the crash, but only once the program terminated, since there was an open "using" and no "end using". Doing this is required for it to be disposed of correctly? Don't know if this was an issue with the original code above or when I transcribed it to VB.net since I am new to programming and autocad, but thought I would document it for any other poor sod.

    Dim tm As Autodesk.AutoCAD.DatabaseServices.TransactionManager = sourceDb.TransactionManager

    Using trans As Transaction = tm.StartTransaction

    ' Open the block table

    Dim bt As BlockTable = CType(tm.GetObject(sourceDb.BlockTableId, OpenMode.ForRead, False), BlockTable)

    ' Check each block in the block table

    For Each btrId As ObjectId In bt

    Dim btr As BlockTableRecord = CType(tm.GetObject(btrId, OpenMode.ForRead, False), BlockTableRecord)

    ' Only add named & non-layout blocks to the copy list

    If (Not btr.IsAnonymous _

    AndAlso Not btr.IsLayout) Then

    blockIds.Add(btrId)

    End If

    btr.Dispose()

    Next

    ' Copy blocks from source to destination database

    Dim mapping As IdMapping = New IdMapping

    sourceDb.WblockCloneObjects(blockIds, destDb.BlockTableId, mapping, DuplicateRecordCloning.Replace, False)

    ed.WriteMessage("Copied")

    End Using

  72. Jason Rosensweig Avatar
    Jason Rosensweig

    Hi Kean,

    This blog has been such a great help. I have a quick question about this post. I'm fairly new to AutoCAD development and tried implementing what you have here for a project I'm working on. The part of the logic I need this for is inside of a transaction and I am getting a eWasOpenForRead error when inserting the block from the source db into the destination db. Outside of the transaction it works however the part where I need this is deeply nested within a transaction. Is there a way to do an UpgradeOpen-like call on the active database or am I forced to call this functionality from outside of the transaction?

    1. Hi Jason,

      It's a little hard for me to respond (partly because I'm not actively working with AutoCAD, these days, but also because the problem isn't completely clear to me).

      Have you tried posting the code to the AutoCAD .NET forum, to see if someone there can help?

      Best regards,

      Kean

      1. Jason Rosensweig Avatar
        Jason Rosensweig

        Thanks for the reply. Basically the eWasOpenForRead exception is occurring at "sourceDb.WblockCloneObjects(..." which I believe is thrown on the destination database. This only happens when i run this code inside of a transaction so I am assuming that opening a transaction has something to do with it. I'm really just looking for a way to accomplish the import of an external block from a drawing resource file within a transaction. As a work around, I moved the code outside of the transaction and it works great. I will post this on the forum though. Thanks for responding so quickly.

  73. Александр Колтаков Avatar
    Александр Колтаков

    Kean, how converting destDB from Database (Autodesk.AutoCAD.DatabaseServices) to AcadDatabase : IAcadDatabase (System.Runtime.InteropServices)?
    Or how import block to database in acadDoc (interface AcadDocument)

    1. Please post support questions to the relevant Autodesk forum.

      Thank you,

      Kean

  74. Jürgen A. Becker Avatar
    Jürgen A. Becker

    Hi Kean,

    the line Autodesk.AutoCAD.DatabaseServices.TransactionManager tm = sourceDb.TransactionManager; doesnt work because there is no TransactionManger Object in Database.
    Do I missing a using or reference?
    Regards Jürgen

    1. Kean Walmsley Avatar

      Hi Jürgen,

      It's very possible, but it's been a long time since I've worked with this code. Please post to the AutoCAD .NET forum: hopefully someone there will have the answer.

      Best,

      Kean

Leave a Reply to Barry Ralphs Cancel reply

Your email address will not be published. Required fields are marked *