System.AccessViolationException when iterating RenderMaterials

Hi! I’ve been having difficulties when iterating RenderMaterialTable and got this error.
My aim is to know if a specific render material exists in the currently opened file to modify it.

Here another error when trying the same behaviour (iterating through the RenderMaterialTable), in this case for purging the non-using RenderMaterials.

You are changing the RenderMaterials table while iterating over it. You should not do that as it causes crashy behavior as you have noticed.

You need to first collect the materials in a list you want to delete in one loop, then loop over the list of materials to delete and remove them from the RenderMaterials table.

This is a common pattern because you never should change a collection you’re iterating over.

@nathanletwory Thanks for the answer!

I’ve modified the code according to your advice, but the problem remains. In the first loop, I just add the material to another new list, but the error appears when accessing the property “Name” of the render material.

public static void CleanRenderMaterials(RhinoDoc doc)
        {
            var matListToDelete = new List<RenderMaterial>();
            for (int i = 0; i < doc.RenderMaterials.Count; i++)
            {
                var renderMat = doc.RenderMaterials[i].Name;

                var inUse = false;
                for (int j = 0; j < doc.Layers.Count; j++)
                {
                    if (doc.Layers.FindIndex(j).RenderMaterial != null && doc.Layers.FindIndex(j).RenderMaterial.Name == renderMat)
                        inUse = true;
                }

                if (!inUse)
                {
                    matListToDelete.Add(doc.RenderMaterials[i]);
                }
            }


            for (int j = 0; j < matListToDelete.Count; j++)
            {
                doc.RenderMaterials.Remove(matListToDelete[j]);
            }


        }```

What RhinoCommon and Rhino version are you using? Rhino command _SystemInfo output would be great.

I’m developing this plugin for Rhino 6 & 7, but I’m testing it in Rhino6.

SystemInfo report

Rhino 6 SR35 2021-8-10 (Rhino 6, 6.35.21222.17001, Git hash:master @ 073ac7b225c67348731c6597127b9410126c3139)
License type: Comercial, build 2021-08-10
License details: Cloud Zoo. In use by: Pedro Cortes (McNeel)

Windows 10.0.0 SR0.0 or greater (Physical RAM: 16Gb)
Machine name: PEDRO-WIN

Computer platform: LAPTOP - Plugged in [100% battery remaining]

Non-hybrid graphics configuration.
Primary display and OpenGL: AMD Radeon Pro 5300M (AMD) Memory: 4GB, Driver date: 11-13-2019 (M-D-Y). OpenGL Ver: 4.6.13571 Compatibility Profile Context FireGL 19.30.03.05 26.20.13003.5002
> Integrated acclerated graphics device with 7 adapter port(s)
- Laptop lid is possibly closed
- Windows Main Display attached to adapter port #1

OpenGL Settings
Safe mode: Off
Use accelerated hardware modes: On
Redraw scene when viewports are exposed: On

Anti-alias mode: 4x
Mip Map Filtering: Linear
Anisotropic Filtering Mode: High

Vendor Name: ATI Technologies Inc.
Render version: 4.6
Shading Language: 4.60
Driver Date: 11-13-2019
Driver Version: 26.20.13003.5002
Maximum Texture size: 16384 x 16384
Z-Buffer depth: 24 bits
Maximum Viewport size: 16384 x 16384
Total Video Memory: 4 GB

Rhino plugins
C:\Program Files\Rhino 6\Plug-ins\Commands.rhp “Commands” 6.35.21222.17001
C:\Program Files\Rhino 6\Plug-ins\WebBrowser.rhp “WebBrowser”
C:\Program Files\Rhino 6\Plug-ins\rdk.rhp “Renderer Development Kit”
C:\Program Files\Rhino 6\Plug-ins\RhinoScript.rhp “RhinoScript”
C:\Program Files\Rhino 6\Plug-ins\IdleProcessor.rhp “IdleProcessor”
C:\Users\pedro.cortes\Desktop\UIMplugin\src\UIM.Rhinoceros\bin\UIM.Rhinoceros.rhp “UIM” 1.0.0.0
C:\Program Files\Rhino 6\Plug-ins\RhinoRender.rhp “Rhino Render”
C:\Program Files\Rhino 6\Plug-ins\rdk_etoui.rhp “RDK_EtoUI” 6.35.21222.17001
C:\Program Files\Rhino 6\Plug-ins\rdk_ui.rhp “Renderer Development Kit UI”
C:\Program Files\Rhino 6\Plug-ins\NamedSnapshots.rhp “Snapshots”
C:\Program Files\Rhino 6\Plug-ins\Alerter.rhp “Alerter”
C:\Program Files\Rhino 6\Plug-ins\RhinoCycles.rhp “RhinoCycles” 6.35.21222.17001
C:\Program Files\Rhino 6\Plug-ins\Toolbars\Toolbars.rhp “Toolbars” 6.35.21222.17001
C:\Program Files\Rhino 6\Plug-ins\3dxrhino.rhp “3Dconnexion 3D Mouse”
C:\Program Files\Rhino 6\Plug-ins\Displacement.rhp “Displacement”

I just tested with a simple file with seven materials in, but no crash:

import scriptcontext as sc

for rm in sc.doc.RenderMaterials:
    print rm.Name

Maybe you could change your code to do a foreach instead? I am not sure how well the index accessor works in loops (it should obviously).

foreach(RenderMaterial rm in doc.RenderMaterials)
{
    // ... your checks here

    if (!inUse)
    {
        matListToDelete.Add(rm);
    }
}

Excelent @nathan !
Changing the for loop to a foreach one solved the problem!
I guess the problem is in the index accesor, as you predicted…

1 Like

Glad that works for you!