I am trying to send a command that I want to run synchronously (Camber SendCommand does it using SendStringToExecute which runs asynchronously) in C3D. I have very simple python script just to get started and see how it is working but it returning ‘__COMObject’ object has no attribute ActiveDocument.
Below is my python code:
import clr
import os
import time
import System
clr.AddReference("AcMgd")
clr.AddReference("AcCoreMgd")
clr.AddReference("Autodesk.AutoCAD.Interop")
from System import *
from Autodesk.AutoCAD.Runtime import *
from Autodesk.AutoCAD.ApplicationServices import *
from Autodesk.AutoCAD.Interop import *
from Autodesk.AutoCAD.ApplicationServices import Application as acapp
changeViewCommand = "-VIEW "
app = System.Runtime.InteropServices.Marshal.GetActiveObject("Autocad.Application")
adoc = app.ActiveDocument
adoc.SendCommand(changeViewCommand)
OUT = True
Another way is to use the SendStringToExecute method.
# Load the Python Standard and DesignScript Libraries
import sys
import clr
# Add Assemblies for AutoCAD and Civil3D
clr.AddReference('AcMgd')
clr.AddReference('AcCoreMgd')
clr.AddReference('AcDbMgd')
clr.AddReference('AecBaseMgd')
clr.AddReference('AecPropDataMgd')
clr.AddReference('AeccDbMgd')
# Import references from AutoCAD
from Autodesk.AutoCAD.Runtime import *
from Autodesk.AutoCAD.ApplicationServices import *
from Autodesk.AutoCAD.EditorInput import *
from Autodesk.AutoCAD.DatabaseServices import *
from Autodesk.AutoCAD.Geometry import *
# Import references from Civil3D
from Autodesk.Civil.ApplicationServices import *
from Autodesk.Civil.DatabaseServices import *
# The inputs to this node will be stored as a list in the IN variables.
dataEnteringNode = IN
adoc = Application.DocumentManager.MdiActiveDocument
editor = adoc.Editor
#adoc.SendStringToExecute("._circle 2,2,0 4 ", True, False, False)
adoc.SendStringToExecute("._zoom _all ", True, False, False)
adoc.SendStringToExecute("_VIEW ", True, False, False)
# Assign your output to the OUT variable.
OUT = 0
You might suggest I should use Batch Save Utility but unfortunately, that doesn’t work. I am trying to run “CONVERTTO3DSOLIDS” command which apparently isn’t part of Core Console as it only loads core assembly files. I tried loading various .dll, .arx files found in C3D installtion directory in core console but it always returned CONVERTTO3DSOLIDS command not found.
If SendCommand doesn’t work, unfortunately I would have to build CONVERTTO3DSOLIDS from scratch in C#.NET
I tried different ways to set adoc variable and it didn’t work. Have you had this working before? I am not doing anything different from what people have suggested online so I am not sure what’s wrong.
Command line cannot be used synchronously, as the DYN runs, then the tool sends.
There are other ways to build automations which rely on more than ACCoreConsole, but they are not super easy to build and are not suitable to drive via Dynamo. If there is an API call (not a command to send) I suggest moving to that method instead which will allow you to stay in dynamo and keep things synched up.
If not you’re onto more complex tools for automation.
Thanks for your insights. Can you please provide a bit more info on what those automations methods might be or provide documentation that I can refer to? I am fluent in coding it out in .NET but due to core console being lean I am not able to run the C3D command “CONVERTTO3DSOLIDS”.
So I don’t know that command and don’t have insight into your workflow for why this is necessary. It may be that you want to do something different earlier in the process.
To find a path forward, start with the civil 3D documentation. Is that command available via the API somewhere? If not, is it in the AutoCAD API somewhere? If not, are parts of it available in either/both so you can string them together? Double check this one closely as you might be missing something if you aren’t very familiar with the relevant aspects of these APIs.
If still not possible, you move onto stuff like macros and other tools… I can’t share much more than that at the moment. Remember that even really good .NET developers need to partner with experts in this space for some of their automation needs - don’t be afraid to bring in a consultant in such cases.
if you need to work with COM Object with PythonNet here 2 solutions
solution using Reflection
import clr
import os
import time
import System
clr.AddReference("System.Reflection")
from System.Reflection import BindingFlags
clr.AddReference("AcMgd")
clr.AddReference("AcCoreMgd")
clr.AddReference("Autodesk.AutoCAD.Interop")
from System import *
from Autodesk.AutoCAD.Runtime import *
from Autodesk.AutoCAD.ApplicationServices import *
from Autodesk.AutoCAD.Interop import *
from Autodesk.AutoCAD.ApplicationServices import Application as acapp
changeViewCommand = "_VIEW "
adoc = Application.DocumentManager.MdiActiveDocument
currentFileName = adoc.Name
print(currentFileName)
com_doc = System.Runtime.InteropServices.Marshal.BindToMoniker(currentFileName)
args = System.Array[System.Object]([changeViewCommand])
com_doc.GetType().InvokeMember("SendCommand", BindingFlags.InvokeMethod, None, com_doc, args)
OUT = True
solution to “cast” ComObjects in the good interface
import clr
import os
import time
import System
clr.AddReference("AcMgd")
clr.AddReference("AcCoreMgd")
clr.AddReference("Autodesk.AutoCAD.Interop")
from System import *
from Autodesk.AutoCAD.Runtime import *
from Autodesk.AutoCAD.ApplicationServices import *
from Autodesk.AutoCAD.Interop import *
from Autodesk.AutoCAD.ApplicationServices import Application as acapp
changeViewCommand = "_VIEW "
adoc = Application.DocumentManager.MdiActiveDocument
currentFileName = adoc.Name
print(currentFileName)
com_doc = System.Runtime.InteropServices.Marshal.BindToMoniker(currentFileName)
IAcadDocument(com_doc).SendCommand(changeViewCommand)
OUT = True
Alternatively you can use IronPython3
for info, the GetActiveObject method is deprecated in NetCore (Civil2025+), I use BindToMoniker here instead (because we can get the filename path)