Rhino.FileIO.File3dm in V6

This one isn’t initially fatal, but the same code works fine under v5. Curious what might have changed

System.AccessViolationException occurred
  HResult=-2147467261
  Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
  Source=RhinoCommon
  StackTrace:
       at UnsafeNativeMethods.ONX_ModelComponentIterator_GetNext(IntPtr modelIterator, Int32& outIndex, ModelComponentType& outType, Guid& outId)
       at Rhino.FileIO.File3dmManifestTable.<GetEnumerator>d__11.MoveNext()
       at Rhino.FileIO.ManifestTable.<GetEnumerator>d__23`1.MoveNext()
       at SMT.SuperWorkCell.ImportWCObjects(Dictionary`2 objDicts, String importPath) in 
  InnerException: 

Here’s the code, exception occurs on the inner loop. If I ignore, it will usually get through it…Of course then my program doesn’t work, as its missing the hundreds of things I needed to import. I also tried opening and saving the targeted file in V6(with new name of course :wink: ). No luck. Also, and maybe its too early to say this. But my V6 is running much slower than the V5…but it could be this method causing all the headache.

public void ImportWCObjects(Dictionary<string, dynamic> objDicts, string importPath)
{
  WorkCellGeo.Clear();
  Rhino.FileIO.File3dmObjectTable components = null;
  IList<Rhino.DocObjects.Layer> layers;
  IList<Rhino.DocObjects.Material> materials;
  Rhino.DocObjects.Material material;
  foreach (string objName in objDicts.Keys)
  {
    Rhino.FileIO.File3dm f3dm = Rhino.FileIO.File3dm.Read(importPath + objName + ".3dm");
    if (f3dm != null)
    {
      components = f3dm.Objects;
      layers = f3dm.Layers;
      materials = f3dm.Materials;
    }
    else { break; }
    foreach (Rhino.FileIO.File3dmObject component in components)
    {
      GeometryBase geom = component.Geometry;
      geom.EnsurePrivateCopy();
      int layerIndex = component.Attributes.LayerIndex;
      int materialIndex = layers[layerIndex].RenderMaterialIndex;
      if (materialIndex > -1)
      {
        material = materials[materialIndex];
      }
      else
      {
        material = Rhino.DocObjects.Material.DefaultMaterial;
      }
      WorkCellGeo[geom] = material.DiffuseColor;
    }
    f3dm.Dispose();
  }
}

Hi Wes,

Is it possible for you to provide a more generic sample, along with a 3dm file, so we can repeat the problem here?

– Dale

yes I will try to split out this method for you…

So I haven’t split this out yet, but I noticed it is still an issue in the newest WIP. I am not getting the error above, but this code

        using (Rhino.FileIO.File3dm f3dm = Rhino.FileIO.File3dm.Read(importPath + MachineModelName + ".3dm"))
        {
            components = f3dm.Objects;
            layers = f3dm.Layers;
            materials = f3dm.Materials;
            for (int i = 0; i < components.Count; i++)
            {
                Rhino.FileIO.File3dmObject component = components[i];
                if (component == null) continue;

component still returns a null. I seem to remember a discussion somewhere about objectTable issues?

Hi Wes,

Can you provide something I can build and run that allows me to reproduce this here?

– Dale

Hi Dale,
I think this will do it.

This command, when set up to run in rhino 5, will import objects from a 3dm file named “TestFile2” located in same path as the active rhino doc.

When run in rhino WIP, it doesn’t work.

    protected override Result RunCommand(RhinoDoc doc, RunMode mode)
    {
        // TODO: start here modifying the behaviour of your command.
        // ---
        string newPath = "";
        string docPath = RhinoDoc.ActiveDoc.Path;

        string[] dirTokens = Regex.Split(docPath, @"\\");
        foreach (string token in dirTokens.Take(dirTokens.Length - 1))
        {
            newPath += token;
            newPath += "\\";
        }
        using (Rhino.FileIO.File3dm f3dm = Rhino.FileIO.File3dm.Read(newPath + "TestFile2.3dm"))
        {
            Rhino.FileIO.File3dmObjectTable components = f3dm.Objects;
            IList<Rhino.DocObjects.Layer> layers = f3dm.Layers;
            IList<Rhino.DocObjects.Material> materials = f3dm.Materials;
            for (int i = 0; i < components.Count; i++)
            {
                Rhino.FileIO.File3dmObject component = components[i];
                if (component == null)
                {
                    RhinoApp.WriteLine("null object");
                    continue;
                }
                else
                {
                    GeometryBase geom = component.Geometry;
                    RhinoApp.WriteLine(geom.ToString() + "_imported");
                }
                // ---
            }
        }
        return Result.Success;
    }
}

Hi Wes,

Just an update on this.

Index access is used only for indexed components (like layers). Model geometry components are not indexed and that’s why the manifest table for geometry components appears empty. The fact that you could access geometry components by index was a bug, which has been fixed for the next Rhino WIP.

Here is the proper workflow:

using (var file = File3dm.Read(filename))
{ 
  RhinoApp.WriteLine($"Object count = {file.Objects.Count}");
  var obj_count = 0;
  foreach (var obj in file.Objects)
  {
    if (null != obj)
      obj_count++;
  }
  RhinoApp.WriteLine($"Objects accessed by enumerating = {obj_count}");
}

– Dale