|
![]() |
Two assemblies have been created to provide access to the earlier COM API. This section briefly describes the assemblies needed in order to access the existing COM API.
The required assemblies for accessing the COM API through .NET are:
-
Autodesk.Navisworks.Interop.ComAPI.dll – This is the generated .NET interop assembly for the COM API.
-
Autodesk.Navisworks.ComAPI.dll – This gives access to the root COM interfaces provided by
-
Autodesk.Navisworks.Interop.ComAPI.dll
This example illustrates how to use the COM API in conjunction with the Navisworks .NET Controls assembly. However the COM API can also be accessed from a Plug-in within Navisworks.
The example queries the UserName property on the root item within each of the Models in a Navisworks file selected by the user at runtime.
Samples illustrating how to use the COM API with the Navisworks .NET API assemblies can be found here.
This example can be found in: '<drive>:\Program Files\Autodesk\Navisworks <Product> 2015\api\net\examples\ Controls\ControlsAndCOM'.
Overview
Step | Key Information |
---|---|
Create blank console project | |
Add API References | Autodesk.Navisworks.ComAPI.dll Autodesk.Navisworks.Interop.ComAPI.dll Autodesk.Navisworks.API.dll Autodesk.Navisworks.Controls.dll |
Add any other references | |
Add code using .NETAPI and COM API | |
Build and run! |
Creating a program to call the COM API
-
Create the calling application.
-
Add the required API references.
-
Add Other references.
-
Enter the code below:
CopyControls and COM
using System; using System.Windows.Forms; //Add the namespaces using Autodesk.Navisworks.Api; using Autodesk.Navisworks.Api.Controls; using Autodesk.Navisworks.Api.Resolver; using ComApi = Autodesk.Navisworks.Api.Interop.ComApi; using ComApiBridge = Autodesk.Navisworks.Api.ComApi; namespace ControlsAndCOM { class Program { [STAThreadAttribute] static void Main(string[] args) { // The "Navisworks.Autodesk.Resolver" assembly should be included in your installation. // Other Navisworks.Autodesk.*" assemblies will be resolved at runtime, // and thus should not be included. // Autodesk.Navisworks.Controls controls usage inside the VS Designer is deprecated, and instead they should be created dynamically. String runtimeName = Resolver.TryBindToRuntime(RuntimeNames.Any); if(String.IsNullOrEmpty(runtimeName)) { throw new Exception("Failed to bind to Navisworks runtime"); } XMain(); } static void XMain() { //Set to single document mode Autodesk.Navisworks.Api.Controls.ApplicationControl.ApplicationType = ApplicationType.SingleDocument; //Initialise the api ApplicationControl.Initialize(); //Create a DocumentControl DocumentControl documentControl = new DocumentControl(); //Set as main document, needs to be called as COM works on the application's MainDocument documentControl.SetAsMainDocument(); //Dialog for selecting the Location of the file to open OpenFileDialog dlg = new OpenFileDialog(); //Ask user for file location if (dlg.ShowDialog() == DialogResult.OK) { //If the user has selected a valid location, then tell DocumentControl to open the file if (documentControl.Document.TryOpenFile(dlg.FileName)) { //Select the first root item using the API ModelItemCollection newSelection = new ModelItemCollection(); newSelection.Add(documentControl.Document.Models.First.RootItem); documentControl.Document.CurrentSelection.CopyFrom(newSelection); //now query the selection using the COM API ComApi.InwOpState10 state; state = ComApiBridge.ComApiBridge.State; foreach (ComApi.InwOaPath path in state.CurrentSelection.Paths()) { ComApi.InwOaNode node; node = path.Nodes().Last() as ComApi.InwOaNode; MessageBox.Show("UserName=" + node.UserName); } } } //Dispose of the DocumentControl documentControl.Dispose(); //Finish use of the API. ApplicationControl.Terminate(); } } }
-
Build and run.
![]() |
---|
SetAsMainDocument must be called when using DocumentControl with the COM API. |
Compatibility with the COM API
The COM API was written without .NET in mind. So it is important to ensure that all related properties are kept from being disposed by the Garbage Collector until the process being worked on is complete. For example, let us look at the following code excerpt.

foreach (InwOaPath path in sel.Paths()) { InwGUIPropertyNode2 propertyNode; List<InwOaProperty> properties = new List<InwOaProperty>(); propertyNode = (InwGUIPropertyNode2)_nwOpState.GetGUIPropertyNode(path, true); foreach (InwGUIAttribute2 attribute in propertyNode.GUIAttributes()) { try { string classUsername = attribute.ClassUserName; if (classUsername.Equals(attributeName)) { foreach (InwOaProperty p in attribute.Properties()) { InwOaProperty property = (InwOaProperty)_nwOpState.ObjectFactory(nwEObjectType.eObjectType_nwOaProperty, null, null); property.UserName = p.UserName; property.value = p.value; properties.Add(property); } break; } } catch (Exception e) { System.Windows.Forms.MessageBox.Show(e.Message + e.StackTrace); } } }
In this example, it could be assumed that everything would work as expected. Indeed, debugging this section of code, where the Garbage collector is less optimized, all could work as expected. However, 'propertyNode' is last used with the call to GUIAttributes(). Once this call has completed, the .NET Garbage Collector would be allowed to delete propertyNode as it is no longer used. In the case of the InwGUIPropertyNode2 class, the removal of propertyNode also deletes the attributes, because of the underlying functionality of the COM API, making calls such as 'attribute.Properties()' throw exceptions.
This problem is not uncommon with .NET programs using COM components and there are a number of solutions to the problem. The simplest solution here is to call GC.KeepAlive(propertyNode) after the loop on GUIAttributes(). KeepAlive, a function of the Garbage Collector class (GC), lets the Garbage Collector know that propertyNode is ineligable for Garbage Collection from the point of declaration to the point where KeepAlive is called.
The fixed code could therefor look like this:

foreach (InwOaPath path in sel.Paths()) { InwGUIPropertyNode2 propertyNode; List<InwOaProperty> properties = new List<InwOaProperty>(); propertyNode = (InwGUIPropertyNode2)_nwOpState.GetGUIPropertyNode(path, true); foreach (InwGUIAttribute2 attribute in propertyNode.GUIAttributes()) { try { string classUsername = attribute.ClassUserName; if (classUsername.Equals(attributeName)) { foreach (InwOaProperty p in attribute.Properties()) { InwOaProperty property = (InwOaProperty)_nwOpState.ObjectFactory(nwEObjectType.eObjectType_nwOaProperty, null, null); property.UserName = p.UserName; property.value = p.value; properties.Add(property); } break; } } catch (Exception e) { System.Windows.Forms.MessageBox.Show(e.Message + e.StackTrace); } } //Call here to keep propertyNode 'alive' through the inner GC.KeepAlive(propertyNode); }
COMApiBridge
This class facilitates using the COM API with the .NET API by providing some methods to aid working between the two APIs.
The State property of the class provides access to the COM API equivalent of MainDocument as can be seen in the example at the beginning of this chapter.
There are also methods for converting between the .NET API ModelItem and the COM API's InwOaPath as well as converting to/from ModelItemCollection and InwOpSelection.