the problem occurs in this sequence:
BlockUser();
SetAllDistAnglMatesDriven();
foreach (ActuatorSensor element in elements)
{
if (element.IsActuator)
{
Feature feat = GetFeatureFromPersID(element.PersistantID);
Dimension dim = GetDimensionFromFeature(feat);
SetDimensionDriving(dim);
}
}
then i modify values of mates, in my code, those mates are the one with element.IsActuator == true. then i call
ReadWriteSensorValues(ref elements);
if the mate is a mate in the top level assembly document, the code works, but for mates from a subassembly of the top level assembly, my method GetValue reads always 0. i have no clue what the root of the problem is, chat gpt cant help, with chat gpt i tried to modify my method GetFeatureFromPersID such that GetObjectByPersistReference3 get called on the ModelDocExtension of the corresponding subassembly document, which does not fix the problem.
here are my used methods:
using SolidWorks.Interop.sldworks;
using SolidWorks.Interop.swconst;
using System;
using System.Collections.Immutable;
using System.Linq;
//the following properties correspond all to the top level assembly document
private readonly ModelDoc2 _modelDoc;
private readonly AssemblyDoc _assemblyDoc;
private readonly ModelDocExtension _modelDocExtension;
private readonly ModelView _modelView;
private void BlockUser()
{
_modelDoc.SetBlockingState((int)swBlockingStates_e.swFullBlock);
}
private void SetAllDistAnglMatesDriven()
//https://help.solidworks.com/2026/english/api/sldworksapi/Get_Mates_and_Mate_Entities_Example_CSharp.htm
//https://help.solidworks.com/2026/english/api/sldworksapi/Traverse_Assembly_at_Component_and_Feature_Levels_Using_Recursion_Example_CSharp.htm
{
TraverseAssemblySubDocs(_assemblyDoc);
//check the mate feature (correct type?, then set driven)
void CheckFeature(Feature feature)
//https://help.solidworks.com/2026/english/api/sldworksapi/SolidWorks.Interop.sldworks~SolidWorks.Interop.sldworks.IFeature_members.html
{
//https://help.solidworks.com/2026/english/api/sldworksapi/SolidWorks.Interop.sldworks~SolidWorks.Interop.sldworks.IFeature~GetTypeName2.html
string type = feature.GetTypeName2();
if (type == "MateLimitDistanceDim" || type == "MatePlanarAngleDim")
{
Dimension dim = GetDimensionFromFeature(feature);
//https://help.solidworks.com/2026/English/api/sldworksapi/SolidWorks.Interop.sldworks~SolidWorks.Interop.sldworks.IDimension~DrivenState.html
//https://help.solidworks.com/2026/English/api/swconst/SOLIDWORKS.Interop.swconst~SOLIDWORKS.Interop.swconst.swDimensionDrivenState_e.html
dim.DrivenState = (int)swDimensionDrivenState_e.swDimensionDriven;
}
}
//travers Mategroup subfeatures in Assembly doc
void CheckAssembly(ModelDoc2 doc)
//https://help.solidworks.com/2026/english/api/sldworksapi/SolidWorks.Interop.sldworks~SolidWorks.Interop.sldworks.IModelDoc2_members.html
{
//https://help.solidworks.com/2026/english/api/sldworksapi/SolidWorks.Interop.sldworks~SolidWorks.Interop.sldworks.IFeatureManager_members.html
//https://help.solidworks.com/2026/english/api/sldworksapi/SolidWorks.Interop.sldworks~SolidWorks.Interop.sldworks.IModelDoc2~FeatureManager.html
FeatureManager featureManager = doc.FeatureManager;
//https://help.solidworks.com/2026/english/api/sldworksapi/SolidWorks.Interop.sldworks~SolidWorks.Interop.sldworks.IFeature_members.html
//https://help.solidworks.com/2026/english/api/sldworksapi/SolidWorks.Interop.sldworks~SolidWorks.Interop.sldworks.IFeatureManager~GetFeatures.html
object[] features = featureManager.GetFeatures(false);
foreach (var currentFeature in features)
{
CheckFeature((Feature)currentFeature);
}
}
//find subassamblies recursive
void TraverseAssemblySubDocs(AssemblyDoc AssDoc)
//source: https://help.solidworks.com/2026/english/api/sldworksapi/SolidWorks.Interop.sldworks~SolidWorks.Interop.sldworks.IAssemblyDoc_members.html
{
CheckAssembly((ModelDoc2)AssDoc);
//https://help.solidworks.com/2026/english/api/sldworksapi/SolidWorks.Interop.sldworks~SolidWorks.Interop.sldworks.IComponent2_members.html
//https://help.solidworks.com/2026/english/api/sldworksapi/SolidWorks.Interop.sldworks~SolidWorks.Interop.sldworks.IAssemblyDoc~GetComponents.html
object[] components = AssDoc.GetComponents(false);
foreach (var currentObject in components)
{
ModelDoc2 currentDoc = null;
Component2 currentComponent = (Component2)currentObject;
//https://help.solidworks.com/2026/english/api/sldworksapi/SolidWorks.Interop.sldworks~SolidWorks.Interop.sldworks.IComponent2~GetModelDoc2.html
if (currentComponent != null) currentDoc = currentComponent.GetModelDoc2();
AssemblyDoc currentAssDoc = null;
if (currentDoc != null)
{
try
{
currentAssDoc = (AssemblyDoc)currentDoc;
}
catch (Exception)
{
//skip, because currentDoc is not an assembly
}
}
//continue recursive search
if (currentAssDoc != null) TraverseAssemblySubDocs(currentAssDoc);
}
}
}
private Mate2 GetMateFromFeature(Feature feature)
{
//https://help.solidworks.com/2026/english/api/sldworksapi/SolidWorks.Interop.sldworks~SolidWorks.Interop.sldworks.IFeature~GetSpecificFeature2.html
return (Mate2)feature.GetSpecificFeature2();
}
private Dimension GetDimensionFromFeature(Feature feature)
//correct mate type not garanteed, call CheckMateType
{
//https://help.solidworks.com/2026/english/api/sldworksapi/SolidWorks.Interop.sldworks~SolidWorks.Interop.sldworks.IFeature~GetSpecificFeature2.html
Mate2 mate = (Mate2)feature.GetSpecificFeature2();
//https://help.solidworks.com/2026/English/api/sldworksapi/SolidWorks.Interop.sldworks~SolidWorks.Interop.sldworks.IDisplayDimension_members.html
//https://help.solidworks.com/2026/English/api/sldworksapi/SolidWorks.Interop.sldworks~SolidWorks.Interop.sldworks.IMate2~DisplayDimension2.html
//only gear has DisplayDimension2[1]
DisplayDimension displayDimension = mate.DisplayDimension2[0] ?? throw new NullReferenceException("DisplayDimension");
//https://help.solidworks.com/2026/English/api/sldworksapi/SolidWorks.Interop.sldworks~SolidWorks.Interop.sldworks.IDimension_members.html
//https://help.solidworks.com/2026/English/api/sldworksapi/SOLIDWORKS.Interop.sldworks~SOLIDWORKS.Interop.sldworks.IDisplayDimension~GetDimension2.html
//If the display dimension is not a chamfer display dimension, then Index is ignored.
Dimension dimension = displayDimension.GetDimension2(0) ?? throw new NullReferenceException("Dimension");
return dimension;
}
private Feature GetFeatureFromPersID(ImmutableArray
{
if (pid.IsDefaultOrEmpty)
throw new ArgumentException("pid is empty.", nameof(pid));
int ok = (int)swPersistReferencedObjectStates_e.swPersistReferencedObject_Ok;
byte[] pidBytes = pid.ToArray();
// Helper: try resolve against a ModelDocExtension, return Feature or throw/return null
Feature TryResolveOnModelDocExtension(ModelDocExtension ext, out int errorCode)
{
if (ext == null)
{
errorCode = (int)swPersistReferencedObjectStates_e.swPersistReferencedObject_Invalid; // arbitrary
return null;
}
object resolved = ext.GetObjectByPersistReference3(pidBytes, out errorCode);
if (errorCode == ok && resolved is Feature feature)
return feature;
return null;
}
// 1) Try top-level doc first (fast path)
{
Feature fTop = TryResolveOnModelDocExtension(_modelDocExtension, out int topErr);
if (fTop != null) return fTop;
// not found at top-level; continue searching components
}
// 2) Recursively traverse components in the top-level assembly and try each component's ModelDocExtension.
// Use only loaded ModelDoc2 instances; if GetModelDoc2() returns null for a component, skip it (we throw detailed exc later if nothing found).
int lastError = -1;
Feature TryResolveInComponent(Component2 comp)
{
if (comp == null) return null;
// Try component's own ModelDoc2 (the component's document instance)
try
{
ModelDoc2 compModel = null;
try { compModel = comp.GetModelDoc2(); } catch { compModel = null; }
if (compModel != null)
{
ModelDocExtension compExt = null;
try { compExt = compModel.Extension; } catch { compExt = null; }
if (compExt != null)
{
Feature f = TryResolveOnModelDocExtension(compExt, out int err);
lastError = err;
if (f != null) return f;
}
}
}
catch
{
// swallow and continue to children — we will surface useful error if nothing found
}
// If not found, recursively try children components (if any)
try
{
// Component2.GetChildren() commonly returns an object[] of Component2; handle defensively.
object childrenObj = null;
try { childrenObj = comp.GetChildren(); } catch { childrenObj = null; }
if (childrenObj is object[] childrenArr)
{
foreach (object childRaw in childrenArr)
{
Component2 childComp = childRaw as Component2;
if (childComp == null) continue;
Feature fromChild = TryResolveInComponent(childComp);
if (fromChild != null) return fromChild;
}
}
else if (childrenObj != null)
{
// if not array, attempt to handle single child
Component2 single = childrenObj as Component2;
if (single != null)
{
Feature f = TryResolveInComponent(single);
if (f != null) return f;
}
}
}
catch
{
// ignore and continue
}
return null;
}
// Get top-level components from the AssemblyDoc.
// Try common GetComponents signatures defensively.
bool triedTopComponents = false;
try
{
object compsObj = null;
try { compsObj = _assemblyDoc.GetComponents(false); } catch { compsObj = null; } // try false (all components)
if (compsObj == null)
{
try { compsObj = _assemblyDoc.GetComponents(true); } catch { compsObj = null; } // fallback: top-level only
}
if (compsObj is object[] compsArr)
{
triedTopComponents = true;
foreach (object compRaw in compsArr)
{
Component2 comp = compRaw as Component2;
if (comp == null) continue;
Feature found = TryResolveInComponent(comp);
if (found != null) return found;
}
}
else if (compsObj is Component2 singleComp)
{
triedTopComponents = true;
Feature found = TryResolveInComponent(singleComp);
if (found != null) return found;
}
}
catch
{
// swallow; we'll throw below if not found
}
// If we get here nothing resolved. Build a helpful exception message.
string msg;
if (!triedTopComponents)
{
msg = "Could not enumerate components from top-level assembly (GetComponents returned null or threw).";
}
else
{
msg = lastError == ok
? "PID was not found in any loaded sub-model's ModelDocExtension."
: \\\$"PID was not found in any loaded sub-model. Last GetObjectByPersistReference3 error code: {lastError}.";
}
throw new Exception(\\\$"Failed to resolve PID across assembly: {msg}");
}
private void SetDimensionDriving(Dimension dim)
{
dim.DrivenState = (int)swDimensionDrivenState_e.swDimensionDriving;
}
private void ReadWriteSensorValues(ref ImmutableArray
{
//if not rebuilt, the dimension dont update
FullRebuid();
foreach (ActuatorSensor element in elements)
{
Feature feat = GetFeatureFromPersID(element.PersistantID);
Dimension dim = GetDimensionFromFeature(feat);
ImmutableArray
double val = GetValue(dim);
builder.Add(val);
element.SensorValues = builder.ToImmutableArray();
}
}
