Hi,
Sorry for asking basic questions - I know it can be annoying answering the same thing over and over... I have googled a lot and searched a lot on here, but I just can't seem to get my head around this.
I basically can't figure out how to write code that works for both AutoCAD 2010 and 2011. The code below works for 2011, but not 2010.
How can I add text to the open drawing in CAD, in a way that works with both versions of AutoCAD (Using only one DLL) ?
Imports Autodesk.AutoCAD.Interop
Public Class Class1
Public ReadOnly Property ThisDrawing As AcadDocument
Get
Return Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.AcadDocument
End Get
End Property
<Autodesk.AutoCAD.Runtime.CommandMethod("FIXSURVEY")> _
Sub TestSub()
Dim basePoint(2) As Double
ThisDrawing.ModelSpace.AddText("Hello World!", basePoint, 5)
End Sub
End Class
From the code itself, it seems OK, with one small thing that I do not like: the VB style of assuming variable's default value:
Dim basePoint(2) As Double
In VB and VB.NET, it seems the basePoint array would have 3 Double elements with value set to 0.0. In general, it would be regarded as best practice that one simply declare a variable without explitly assigning a value before using it. In C#, the compiler would warn you that a variable is used without be assigned. In VB/VB.NET one can get away with this, (and even some VBers like this kind of shortcut), it is often a source of potentially very subtile bug.
However, it probably is not the cause of your problem. My guess would be that you write the code with Acad2011's COM API referenced, and trying to run the code on a computer with only Acad2010 installed. Although Acad2010 and 2011 (and possibly 2012) are the same major release version (18.x), later version's acad type library (both acad and objectDBX common library) only backward compatible. That is, if your code references Acad2010's COM type library, it would most likely work on computer with Acad2011 and future 2012, while if your code references later version of COM type library, it may not work on on computer only with earlier version of AutoCAD installed.
Actually, this kind of thing could also happens to pure .NET API code, but COM API libraries would more sensitive to version change, because COM's "DLL Hell" problem (no different version of the same class can co-exist).
Try compile your code against Acad 2010 type libraries and run it in computer with only Acad2011installed. (If your computer has both Acad2010 and Acad2011 installed, your test may not good enough, because Acad2011 installation has already updated the COM library to Acad2011 version (acax18enu.tlb) and you do not have Acad2010 version in your computer any more.
Also, even the code of creating Text entity with COM API looks simple in .NET API project, I'd not recommens to freely use COM API in .NET API project as if one is still doing thing in VBA. Unnecessarily to add dependency to COM API, which can easily get the code into "DLL Hell" isn't as good practise as one should. With AutoCAd's .NET API, one can do more than with COM API. Just because of .NET API provides easy access to COM API objects does not mean it is good to use freely.
Norman Yuan
Is there a reason you are using the COM interface instead of the regular .NET API?
I haven't done much COM (interop) programming but the little I've done it's always been a pain dealing with different year (and bit versions) of AutoCAD.
Using the regular .NET API you would reference the dll included in the 2010 ObjectARX SDK include folder and it would work in 2010/2011/2012 (32bit & 64bit) applications. If you are not using something that is only accessable via COM I would stck with the .NET API.
Thank you so much for taking the time to write an in-depth answer to my question - I really appreciate it. It clears up a lot of the gaps I have in my understanding.
I get that COM is the old way that vba uses, and .NET is the new way, but how do I know in my code which is old and new? I gather it's something to do with my references:
I'm thinking now that I should get rid of the Autodesk.AutoCAD.Interop references altogether. Interesting to note the path for them has changed! I used the files in C:\ObjectARX 2011\inc-x64
There is a reason yes - because I don't know what I'm doing!
When you say I should only use references that are in the include folder of the ObjectARX SDK, I thought that was what I did:
AcDbMgd < C:\ObjectARX 2011\inc
AcMgd < C:\ObjectARX 2011\inc
Autodesk.AutoCAD.Interop < C:\ObjectARX 2011\inc-x64
Autodesk.AutoCAD.Interop.Common < C:\ObjectARX 2011\inc-x64
I'm guessing the .NET way uses a different way to add text than somedocument.modelspace.addtext(arg1,arg2,arg3) or something ?
Thanks for your help
Firstly, for doing Acad .NET API development, ObjectARX SDK is not a MUST. you can directly set reference to acadmgd.dll and acmgd.dll in Acad installation directory. In most cases, these 2 are all you need.
You do not need to use COM API, exposed by Autodesk.AutoCAD.Interop and/or ...interop.common in most cases. In the early stage of Acad .NET API (Acad2005/6), ther were many basic functionalities missing from .NET API, such as there weas no easy way to do a simple zoom, the easy access to COM API from .NT API helps. With more and more advance of .NET API, there would be less chance one has to turn to COM API to help.
If in certain case you do need to use COM API, you can set reference in the "References" dialog box, COM tab to the ....interop/...Interop.Common, which as PIA installed in the GAC by Acad installation. So, SDK is not really something you have to use. That is, AutoCAD itself has all the needed DLLs you need for development installed. That is why you need to set "Copy Local" to False for these references.
However, the same dll from SDK has removed some dependencies to AutoCAD, so that programmer can use that references in a more isolated environment. For example, the developement can be open or even develop in a computer without Acad installed (of course you cannot do debugging, then). That is another why you should make it very sure to set "Copy Local" to False: The dlls from SDK are for development ONLY. You might have noticed, the size of acadmgd/acmgd.dll from SDK is much smaller than the once coming with AutoCAD.
You may be using ObjectARX managed project wizard to start your project, which I personally do not like. It unnecessarily add extra references to the project, such as WPF's Presentation.Core.dll, acWindows.dll, and maybe AutoCAD.Interop (I am not sure), while in most .NET API development, you only need acdbmgd/acmgd.dll.
Also, path to Autodesk.AutoCAD.Interop/Interop.Common being changed or not really does not matter, they are installed in GAC by AutoCAD. If you set reference to them from SDK folder (or anywhere in the disk), you do not copy them to output location (Copy Local =False) anyway, and AutoCAD (actually the .NET runtime) always look for it in GAC first.
So, I do recommand the start a blank class library project (VB.NET or C#), set references to acdbmgd/acmgd.dll(make sure "Copy Local to Flase), maybe add some boiler plate code in a class and then export it as your basic Acad .NET API development template. Then go to SDK's sample folder for .NET samples to learn manipulate Acad entities and environment in .NET way, as opposed to COM way. The differences are quite significant. As one with quite some VBA backgroud, one may feel the .NET way are a lot more complicated. But one would not regret in the end for the transition.
Norman Yuan
Will
I have attached some sample code of how this is done in .NET as a sample. I don't know if you have looked over the AutoCAD .NET developers guide, but it is a great place to start. I have not tested what I am posting, but just wrote it from memory so I hope it will be a starting place for you.
Imports Autodesk.AutoCAD Imports Autodesk.AutoCAD.DatabaseServices Imports Autodesk.AutoCAD.Runtime Imports Autodesk.AutoCAD.ApplicationServices Imports Autodesk.AutoCAD.Geometry Public Class Class1 <CommandMethod("FIXSURVEY")> Sub TestSub() Dim acMText As New MText acMText.Contents = "Hello World!" acMText.Location = New Point3d(5, 5, 0) AddEnt(HostApplicationServices.WorkingDatabase, acMText, True) ' adds the text to model space AddEnt(HostApplicationServices.WorkingDatabase, acMText, False) ' adds the text to paper space End Sub Public Sub AddEnt(ByVal acDB As Database, ByVal acEntity As Entity, ByVal acModelSpace As Boolean) Using TR As Transaction = acDB.TransactionManager.StartTransaction Dim acBT As BlockTable = acDB.BlockTableId.GetObject(OpenMode.ForRead) Dim BTR As BlockTableRecord If acModelSpace Then BTR = acBT(BlockTableRecord.ModelSpace).GetObject(OpenMode.ForWrite) Else BTR = acBT(BlockTableRecord.PaperSpace).GetObject(OpenMode.ForWrite) End If BTR.AppendEntity(acEntity) TR.AddNewlyCreatedDBObject(acEntity, True) TR.Commit() End Using End Sub End Class
you will find that the addent sub can be used for lines and other entities as well as text.
..quick thanks to those who took the time to explain things ....hugely valuable insights for ankle snappers like us.
Yes I really want to echo that - Very much appreciate your efforts in these very good explanations. If you're interested, my first .NET application is in circulation here:
http://howtoautocad.com/autocad-civil-3d-survey-fix-tool/
Thanks again!
Will
classic tool Will on your website. We wrote something similarfor use in ACA but transformed the text into points - we weren't clever enough to use some kind of proximity routine.
That was the day I realised that it's not running the latest AutoCad version that gets the job done faster and better...its being able to write macros.
We had Revit re-sellers in again yesterday...they still can't achieve -actually can't even get close - to the kind of data manipulation we can do with ACA and Visual Basic - for urban design.
Can't find what you're looking for? Ask the community or share your knowledge.