Hi all,
Sorry for my basic type of question in advance.
I have already developed my VB.NET Windows Form app (.NET 4.0 in VS2012) which does some Windows operation on roughly hundreds of AutoCAD drawing files(e.g. purely copy/move/rename type of actions).
Now I need to tell my app to communicate with AutoCAD 2013 and collect some attributes from a specific existing block in all of these drawings and then replace the collected values with some other values passed to AutoCAD by my Form application (see diagram below if that helps: )
I had a look to couple of AutoCAD .NET blogs and realised how to make DLL files and leverage NETLOAD tool in AutoCAD afterwards but I am afraid DLL files and NETLOAD are not what I am looking after (correct me if I am wrong).
At this stage I am not asking for any coding assistance but rather I would like to clearly know what is the best pathway to achieve my goal described above.
Regards
Moji
Hi,
Usually to run a program on hundreds of files, user will not intend to open AutoCAD and run the program. He will expect a Windows Application which does the operation silently in the background without the graphical interface of AutoCAD.
But Autodesk recommends to run the program inside AutoCAD.
Hope this clears your pathway
Thanks for the reply santoshr0114,
Well yes and no about being clarified.
I dont mind perofrming all operations behind the scene (even prefered) but don't know how to achive that.
Currently I have splited my goal to two section:
Have no freaking idea how to combine these two steps though
Suggections welcomed.
Cheers
Your Windows Form should load an instance of AutoCAD.
Once the AutoCAD instance is loaded. run your function to perfom the task
To do this outside of AutoCAD and by not using Netload you need to used AutoCAD Interop
The Below Sample might get you started
Imports Autodesk.AutoCAD.Interop Public Function GetAcadApp() As AcadApplication Dim progID As String = My.Settings.strAcadProgID Dim acApp As AcadApplication = Nothing Try acApp = DirectCast(Marshal.GetActiveObject(progID), AcadApplication) Catch ex As Exception Try Dim acType As Type = Type.GetTypeFromProgID(progID) acApp = DirectCast(Activator.CreateInstance(acType, True), AcadApplication) Catch ex2 As Exception MessageBox.Show("Cannot create object of type """ & progID & """") End Try End Try If acApp IsNot Nothing Then End If Return acApp End Function
There was a compilation error with your code:
'strAcadProgID' is not a member of '[...].My.Settings'.
However, after replacing it by this:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Dim AppComObj As AcadDocument = Nothing Dim ProgId As String = "AutoCAD.Application.19" Try AppComObj = GetObject(, ProgId) Catch ex As System.Exception Try ' Create a new instance of AutoCAD AppComObj = CreateObject(ProgId) Catch ex2 As Exception MsgBox(ex2.Message) Exit Sub End Try End Try AppComObj.Visible = True End Sub
I got no compilation error but sadly after triggering the code, this message pops up:
To be more precise, this is how my project reference setup looks like:
and I have imported followings:
Imports System.IO Imports Autodesk.AutoCAD.Interop Imports Autodesk.AutoCAD.Interop.Common
That was just a sample code to get you started. You have to change the code as per your needs.
Anyways the below code works for me.
public void OpenAutoCAD() { const string progID = "AutoCAD.Application"; try { acApp = (AcadApplication)Marshal.GetActiveObject(progID); } catch { try { Type acType = Type.GetTypeFromProgID(progID); acApp = (AcadApplication)Activator.CreateInstance(acType, true); } catch { MessageBox.Show("Cannot create object of type \"" + progID + "\""); } } if (acApp != null) { try { // By the time this is reached AutoCAD is fully // functional and can be interacted with through code acApp.Visible = false; } catch (Exception ex) { MessageBox.Show(this, "Problem executing component: " + ex.Message); } } }
convert the same code to vb.net
Remove the references of AcCoreMgd, AcDbMgd, AcMgd.
And you are creating a Windows Application(.exe) not a class library(.dll) right?
Thank you so much. Simply added following line to it and it works like a charm:
Dim acApp As AcadApplication = Nothing
Regarding your question, I am creating an EXE file at the end of the day. But as I mentioned in previous posts, this EXE application should be able to leverage NETLOAD command in AutoCAD and load my dll library.
So, now, can you please tell me how can I inject an OPEN functionality in my 'try...catch' block. i.e. I want to have s/th like this in my try..catch block:
OpenDWG("c:\test.dwg")
In other words I need to call function to open a dwg document in AutoCAD session which has been just launched invisible.
The last step would be calling "NETLOAD" command for my opened *.dwg file.
Cheers
Why do you need to call the netload command when all the fucnionality can be acieved without usig Netload.
to open just use AcadDocument doc = AcadApp.Documents.Open(DWGFILEPATH);
and then activate using doc.acivate();
then once the document / drawing is active you can perform your task to getting or updating the attributes.
Dealing with drawing via COM sounds more pleasant to me but I dont know how to convert my class library codes to be acceptable for COM. I had some codes in my DLL file to purge and also to update some attributes.
Here is the code which I was using to Purge (in DLL file):
Private Sub PurgeBlocks() Dim doc As Document = Application.DocumentManager.MdiActiveDocument Dim ed As Editor = doc.Editor Dim db As Database = doc.Database Using trans As Transaction = db.TransactionManager.StartTransaction() Dim bt As BlockTable = TryCast(trans.GetObject(db.BlockTableId, OpenMode.ForWrite), BlockTable) For Each oid As ObjectId In bt Dim btr As BlockTableRecord = TryCast(trans.GetObject(oid, OpenMode.ForWrite), BlockTableRecord) If btr.GetBlockReferenceIds(False, False).Count = 0 AndAlso Not btr.IsLayout Then btr.[Erase]() End If Next trans.Commit() End Using End Sub
And these ones to update some attributes(in DLL file):
Private Sub UpdateAttributesInDatabase(db As Database, blockName As String, attbName As String, attbValue As String) Dim doc As Document = Application.DocumentManager.MdiActiveDocument Dim ed As Editor = doc.Editor ' Get the IDs of the spaces we want to process and simply call a function to process each Dim ModelSpaceId As ObjectId Dim PaperSpaceId As ObjectId Dim Transactn As Transaction = db.TransactionManager.StartTransaction() Using Transactn Dim bt As BlockTable = DirectCast(Transactn.GetObject(db.BlockTableId, OpenMode.ForRead), BlockTable) ModelSpaceId = bt(BlockTableRecord.ModelSpace) PaperSpaceId = bt(BlockTableRecord.PaperSpace) Transactn.Commit() End Using UpdateAttributesInBlock(ModelSpaceId, blockName, attbName, attbValue) UpdateAttributesInBlock(PaperSpaceId, blockName, attbName, attbValue) ed.Regen() End Sub '============================================================ Private Sub UpdateAttributesInBlock(btRecordId As ObjectId, blockName As String, attbName As String, attbValue As String) Dim doc As Document = Application.DocumentManager.MdiActiveDocument Dim db As Database = doc.Database Dim ed As Editor = doc.Editor Dim tr As Transaction = doc.TransactionManager.StartTransaction() Using tr Dim btRecord As BlockTableRecord = DirectCast(tr.GetObject(btRecordId, OpenMode.ForRead), BlockTableRecord) For Each entId As ObjectId In btRecord Dim ent As Entity = TryCast(tr.GetObject(entId, OpenMode.ForRead), Entity) If ent IsNot Nothing Then Dim br As BlockReference = TryCast(ent, BlockReference) If br IsNot Nothing Then Dim bd As BlockTableRecord = DirectCast(tr.GetObject(br.BlockTableRecord, OpenMode.ForRead), BlockTableRecord) 'to see whether it's a block with the name we're after If bd.Name.ToUpper() = blockName Then ' Check each of the attributes... For Each attReferenceId As ObjectId In br.AttributeCollection Dim obj As DBObject = tr.GetObject(attReferenceId, OpenMode.ForRead) Dim attReference As AttributeReference = TryCast(obj, AttributeReference) If attReference IsNot Nothing Then 'to see whether it has the tag we're after If attReference.Tag.ToUpper() = attbName Then ' If so, update the value and increment the counter attReference.UpgradeOpen() attReference.TextString = attbValue attReference.DowngradeOpen() End If End If Next End If UpdateAttributesInBlock(br.BlockTableRecord, blockName, attbName, attbValue) ' Recurse for nested blocks End If End If Next tr.Commit() End Using End Sub
Any idea for getting their equivalent for COM mode? I dont mind using any other code as long as it provides my the following functionalies:
Alternatively, if I could not find any solution for conversion, how can I load a DLL code using "NETLOAD" command?
Explore more COM objects. like AcadDocument, AcadBlockReference, AcadEntity, AcadBlockReference.
Using these you can update atributes using com
I am still not sure why do you need "netload"
I will advise soon. Thanks for that. I need more sample codes for COM. That's all
@Anonymous wrote:
Explore more COM objects. like AcadDocument, AcadBlockReference, AcadEntity, AcadBlockReference.
Using these you can update atributes using com
That was a thought for doomsday. Not serious though - until I could turn my head around COM solutions.
@Anonymous wrote:I am still not sure why do you need "netload"
You cannot find samples using COM easily. Search on CAD forums
You have to explore more on yourself rather than finding samples. Searching will eat your time.
If i come acoss any i can help you.
And its good to be prepared for doomsday.
@Anonymous wrote:Why do you need to call the netload command when all the fucnionality can be acieved without usig Netload.
to open just use AcadDocument doc = AcadApp.Documents.Open(DWGFILEPATH);
and then activate using doc.acivate();
then once the document / drawing is active you can perform your task to getting or updating the attributes.
Sorry, you're not really offering very good advice here.
Interprocess COM is extremely slow, and that is why loading the part of the application that does the heavy-lifting into AutoCAD's process is the preferred solution.
The OP can achieve that in one of two ways:
1. NETLOAD the in-process component into AutoCAD via NETLOAD, executed using SendCommand() and invoke a command registered by the in-process component using SendCommand(). This is not the preferred solution because it is not synchronous, and therefore, the caller will not be able to wait until the process has completed.
2. Expose the in-process component as a COM object, that would be accessed from the out-of-process component using the AcadApplication's GetInterfaceObject() method. This is the preferred solution, because it can be made fully-synchronous, allowing the caller to wait until the in-process component has completed its task on each file before moving on to the next file.
When using option 2, the in-process COM object must be derived from System.ServiceModel.ServicedComponent to ensure that it runs in the STA threading context.
Thanks for the contribution DiningPhilosopher. Can you tell me more about your "option 2"? The current provided description sounds far beyond my knowledge on AutoCAD VB.NET programming. I am trying to improve though.
Therefore, a primitive approach i.e. communication with AutoCAD via COM looks more achievable option to me. Moreover, the speed is not super critical for my application. At this stage, the main purpose is to deliver the given task in a logical way.
Cheers
Implementing a COM object in .NET that can be loaded into AutoCAD's process is fairly-advanced, and I don't have any VB.NET examples of that (or even a C# example that is 'bare-bones').
If speed is not critical, and you can do the job synchronously from another process then it may be the best approach given your ability, but it will be painfully-slow.
I agree to your opinion DiningPhilosopher. But i haven't tried Exposing the in-process component as a COM object and i am not aware of the possibilites.
And i already suggested using In-Process communication in my first post as reply.
As the user will will be processing bunch of drawings at a time, so suggested using COM component. And yes the processing time is very slow compared to In-Process communication
Can't find what you're looking for? Ask the community or share your knowledge.