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 (NavisworksIntegratedAPI10.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.
22 | Autodesk Navisworks COM Interface
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 (NavisworksIntegratedAPI10.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 loop
GC.KeepAlive(propertyNode);
}