Managing Multiple Rhino 8 Instances in Headless Mode

Hello everyone,

I’m developing a C# application that needs to run Rhinoceros 8 in headless mode to perform background processing tasks. Multiple instances of this application can run at the same time, each one launching a different Rhino instance.

To launch Rhino, I’m using code based on the Automation Sample in the following way:

private dynamic rhino;

try {
    const string rhino_id = "Rhino.Application.8";
    var type = Type.GetTypeFromProgID(rhino_id);
    rhino = Activator.CreateInstance(type);
} catch (Exception e){
   // exception handling
}

if (null == rhino) {
         // error handling
}

while (0 == rhino.IsInitialized()) {

    Thread.Sleep(100);

    time_waiting += 100;

    if (time_waiting > bail_milliseconds) {
         // error handling
    }
}
 

The Issue:

In some cases—especially when Rhino doesn’t have an active license or cannot open properly—my application hangs indefinitely during the CreateInstance call. The exception catch block is not triggered, so the application stays in the Activator.CreateInstance(type); line without handling the error.

Problem Details:

The behavior I’m seeing is unpredictable and inconsistent:

• Sometimes each instance of my process creates and launches Rhino one at a time. After about a minute, the Rhino instances close, and the exception is caught.

• Other times it takes 20 minutes, or it hangs indefinitely.

• Occasionally, multiple Rhino instances launch simultaneously, or Rhino continues running even after the calling process has been terminated.

This unpredictability is problematic because:

  1. I don’t receive a handle to the Rhino process from Activator.CreateInstance, so I can’t close specific instances directly.

  2. Rhino doesn’t terminate when my application closes, leading to accumulated instances over time, which could affect system performance.

Question:

How can I reliably detect and manage Rhino instances created by my application? Specifically:

• Is there a way to ensure Rhino closes when the calling process is terminated?

• How can I prevent multiple lingering Rhino instances if there’s an issue launching it?

Thank you in advance for any advice!

Hi @Claudio_Gianfrate that sample looks to be about 12 years old .

I’d consider using Rhino.Inside myself which will work a lot better and give you a lot more opportunities.

Thanks @CallumSykes for the response! I have some follow-up questions:

  1. When running Rhino.Inside, is the Rhino instance created as a child process? If not, how can I ensure it terminates when the caller process ends?

  2. Currently, our code loads a custom plugin (built with RhinoCommon) and executes its functions as shown below:

private dynamic rhino;

[...]
    rhino = Activator.CreateInstance(type);
[...]

// Set Rhino instance headless
rhino.Visible = 0;

// Get custom plugin
dynamic? plugin = null;
try {
    plugin = rhino.GetPluginObject("pluginID", "pluginID");
} catch (Exception e) {
    // exception handling
}

[...]
// Execute plugin functions
plugin.Function1(args);
plugin.Function2(args)

Could you advise on the correct way to load a plugin with Rhino.Inside?

  1. We’re already trying to refactor this to work with Rhino.Inside, but encountered a problem with the setup code:
class Program
  {
   
    static Program()
    {
      RhinoInside.Resolver.Initialize();
    }

    [System.STAThread]
    static void Main(string[] args)
    {
        using (new RhinoCore(args)) {
          //Do stuff...
        }
    }
  }

However, when running this, we get a runtime error:

Unhandled exception. System.IO.FileNotFoundException:
Could not load file or assembly ‘RhinoCommon, Version=8.12.24282.7001, Culture=neutral, PublicKeyToken=552281e97c755530’. The system cannot find the file specified.
File name: ‘RhinoCommon, Version=8.12.24282.7001, Culture=neutral, PublicKeyToken=552281e97c755530’

We’re using .NET 6.0, and while Rhino.Inside (Version 7.0.0) officially requires .NET Framework 4.8, I’ve seen forum posts suggesting this might not be a hard requirement. Could you clarify if there’s a way to resolve this or any workarounds?

You should be able to use RhinoCore.Dispose() with the RhinoCore which will get created when you use Rhino.Inside. You can see this being done with a using in the samples.

I believe I’ve always used Rhino.PlugIns.LoadPlugin(...) https://developer.rhino3d.com/api/rhinocommon/rhino.plugins.plugin/loadplugin to ensure it’s loaded.
As for grabbing the active instance. You should not create your own instance, Rhino will do that for you. Are you able to reference your plugin from this project? If not you’ll need to do some System.Reflection, or dynamics as you’ve done.

I’m also getting this with the sample so let me look into this.

I would suggest using net7.0 (over net6.0), that’s what Rhino 8 is using. Currently our Nugets are published to net48 only, but you can use those via netcore.

Thanks for the advice! I’ll give it a shot in a .NET Framework 4.8 project.

After some debugging, I think I’ve pinpointed the issue. When I install the latest RhinoInside (version 7.0.0), it automatically installs RhinoCommon, Grasshopper, and RhinoWindows at version 7.0.20314.3001. However, if a different version of RhinoCommon is already installed, RhinoInside attempts to link to that version instead. This causes a runtime error if the version is higher than 7.0.20314.3001, as RhinoInside 7.0.0 isn’t compatible with newer versions.

Additionally, RhinoCommon 7.0.20314.3001 isn’t compatible with .NET 6.0, so for now, switching to .NET Framework 4.8 seems to be the only way to get it working. Do you think upgrading to .NET 7.0 would make a difference here?

I had a similar (unsolved) Issue here:

would be nice to have an updated example.

1 Like

@CallumSykes Just an update. We’ve rewritten our code in a .NET Framework 4.8 project as follows:

class Project
    {
        static Project()
        {
            RhinoInside.Resolver.Initialize();
        }

        [System.STAThread]
        static int Main(string[] args)
        {
            //Do some checks [...]
            try
            {
                // Try creating an instance of Rhino
                using (new RhinoCore(new string[] { "/NOSPLASH" }, WindowStyle.Hidden))
                {
                    //Do some other stuff [...]

                    //Load plugin
                    if (PlugIn.LoadPlugIn(pluginId))
                    {
                        //Launch Plugin Command
                        RhinoApp.RunScript("Plugin Command");
                    }
                }
            }
            catch(Exeption e)
            {
                //Handle exeption...
            }

            return someValue;
        }
    }
 

This code runs without issues when executed one instance at a time. However, when we try running multiple instances, we encounter different behaviors depending on the caller:

Console Execution: The process stops after RhinoApp.RunScript(“Plugin Command”); (we’re investigating this to determine the root cause inside the Plugin, but it seems a concurrency issue).

Windows Service Execution: If the process is instantiated by a Windows Service that manages a queue, it fails when trying to create a new Rhino instance with new RhinoCore(new string[] { “/NOSPLASH” }, WindowStyle.Hidden), returning the error “Error HRESULT E_FAIL has been returned from a call to a COM component.”

It seems Rhino.Inside doesn’t support multiple Rhino instances running simultaneously. I found a related forum thread suggesting that, instead of running multiple threads with Rhino.Inside in a Windows Service, each instance should be in a separate process, but this is exactly what we have at the moment:

My question is: what specifically prevents multiple Rhino instances from being created across different processes? Is there a known limitation with Rhino.Inside regarding this behavior? Should we call the RhinoCore constructor with a specific parameter?

I think it would be good to understand what you are trying to accomplish inside your plugin that requires you to spin up all these Rhino instances? It’s a lot of overhead and complexity, and it might be possible to avoid all of this if we understand what the functions inside your plugin do.

It sounds like we need to figure out how to get Rhino.Inside to run for you with a single instance console application first. If this isn’t working, then that’s a likely reason multiple instances are not working.

I suspect the problem is stemming from calling RunScript in a mode where there is no UI and very likely no Rhino Doc.

How do you have Rhino license installed on your machine? If you are using Cloud Zoo and have logged in using an ordinary user account, that might not work when run in the context of a system account. I recommend using single-computer licensing to lock the license to one workstation.

At this stage of the project, we abandoned trying Rhino.Inside (we couldn’t afford switching to a solution that doesn’t work mid-project) and reverted to using headless Rhino. We also implemented a mechanism to clean up lingering Rhino processes. Rhino.Inside remains an option only if we can fully address its issues.

To get the integration working reliably, we configured the service and Rhino.Application.8 COM object as follows:

  • Windows Service: The Log On property is set to a specific local account USER with administrator privileges.
  • DCOM Configuration: The Identity properties are configured with “This user” with USER credential, in the Security tab full permissions are granted to USER.

With this setup, the service runs successfully and launches multiple Rhino instances on a Windows 10 machine.

However, the same configuration on a Windows Server 2018 machine fails. The error occurs at the Activator.CreateInstance line:

“Retrieving the COM class factory for component with CLSID {88FAF7D3-0C9D-4FFE-BD48-794D1E43DD52} failed due to the following error: 80080005 Server execution failed (0x80080005 (CO_E_SERVER_EXEC_FAILURE)).”

I observed that Rhino launches but hangs for 60 seconds before closing, leading to the error. My suspicion is that Rhino encounters an error during startup, stalls with a UI error, and fails to register with DCOM within the required timeout. This suspicion is confirmed by the following entry in the Windows System Event Log:

“The server {88FAF7D3-0C9D-4FFE-BD48-794D1E43DD52} did not register with DCOM within the required timeout.”

I also utilized ProcMon to investigate what’s happening under the hood, and it seems my assumption is correct. When Rhino is launched normally, it successfully contacts Cloud Zoo to verify the license. However, in the background process, this license verification step doesn’t occur at all.

Unfortunately, we couldn’t gather more details about the error. It would be extremely helpful to have access to some form of logging to better understand the issue.

Are there any known issues with running Rhino this way on Windows Server? Are there specific challenges with Windows Services interacting with Rhino? Additionally, is there a debug log available during the DCOM object startup, or a way to launch Rhino not headless to diagnose this problem?

In the Rhino - System Requirements under Not Supportedit says: Windows Server (any version)

To run Rhino on Windows Server you need core-hour billing set up: Rhino - Licensing & Billing

Thank you for your answer. I’m sticking to the original solution running on Windows 10 (with plans to upgrade to Windows 11 in the future).

I would like to understand the correct way to configure Rhino licenses to ensure proper functionality in this scenario.
We tested the application with a Single Computer License, but it was not possible to run more than one instance simultaneously in headless mode (is it possible that the limitation described here applies not only to Windows Server?).

Using a Cloud Zoo license, however, we encountered no issues. The same problem arises with a Lan Zoo license. What is the correct way to set up the Lan Zoo license server in this type of scenario?

@nathanletwory @brian @CallumSykes

That’s strange. Rhino should run just fine with multiple instances using single-computer licensing. Can you please send more details of your setup so we can try to reproduce it here?

Thanks for your response, @brian. Let me clarify the setup further, maybe it wasn’t clear for my previous posts.

I have a Windows Service that launches multiple separate processes using .NET Process.Start. Each of these processes, launches headless Rhino instances using the following code (same as in my original post):

private dynamic rhino;

try {
    const string rhino_id = "Rhino.Application.8";
    var type = Type.GetTypeFromProgID(rhino_id);
    rhino = Activator.CreateInstance(type);
} catch (Exception e){
   // exception handling
}

if (null == rhino) {
         // error handling
}

while (0 == rhino.IsInitialized()) {

    Thread.Sleep(100);

    time_waiting += 100;

    if (time_waiting > bail_milliseconds) {
         // error handling
    }
}

The Windows Service runs under a specific local user account (not LocalSystem). Also the DCOM configuration for Rhino.Application.8 is set to run under the same local user in the “Identity” settings.

The service successfully launches and manages multiple processes on Windows 10, but we encountered licensing issues when running multiple instances at the same time.

  • With Single Computer Licensing, only one instance runs at a time, and additional instances fail with the following error: Retrieving the COM class factory for component with CLSID {88FAF7D3-0C9D-4FFE-BD48-794D1E43DD52} failed due to the following error: 80080005 Server execution failed (0x80080005 (CO_E_SERVER_EXEC_FAILURE)).
  • With Cloud Zoo, multiple instances at the same time work fine without any issues.
  • With LAN Zoo, we encountered similar restrictions as Single Computer Licensing, where multiple instances do not work.

So my questions are:

  1. Should Single Computer Licensing allow multiple instances when running headless? If not, is this an intended restriction?
  2. Should LAN Zoo licensing work in this scenario? If so, is there a specific configuration required to allow multiple concurrent headless Rhino instances with LAN Zoo?

Any insights into whether LAN Zoo needs additional setup for headless automation would be extremely helpful. Thanks again for your time!

@AndyPayne is this something you can help with? It’s over my head :smiley:

Hi Claudio,
It does seem like a Single Computer License should work (that’s basically what we use with Rhino.Compute when it starts up under the Grasshopper process). However, this begs the question… Is there a reason you can’t use the standard Rhino.Compute project to do this? If you pull down the source code (in the link above) and open the compute.sln and then run this… it should start a process (rhino.compute.exe) which will then spawn multiple headless instances of compute.geometry.exe which can then be communicated with over REST calls.
If you’re interested in simply implementing this all yourself, then I would recommend at least looking at the ComputeChildren.cs file in that repo… specifically the function called LaunchCompute. This function is where we actually handling spinning up each of the headless instances and perhaps it will help you integrate a similar function into your own application. Does this help you?

Hi Andy,

Thanks for your response!

The project I’m working on is a simple queue manager to execute a specific task written as a Rhino plugin. I intentionally wanted to avoid the additional complexity of a REST server and the websocket, which comes with Rhino.Compute.

From what I see in the LaunchCompute function, you spawn a new compute.geometry.exe process and then connect to it via WebSocket. My question is: Is there a way to simply start a new Rhino instance in headless mode without relying on compute.geometry.exe?

We also explored Rhino.Inside, but as I mentioned in this post, we encountered issues when trying to run multiple Rhino instances simultaneously.

Would appreciate any insights on a direct approach without Compute.

Thanks again!

The compute.geometry.exe is the actual headless mode of Rhino. It’s the process that actually does all of the work (ie. computation). The rhino.compute.exe is just a parent layer which handles spinning up all the child processes (ie. compute.geometry) and forwards the requests to each child.

I think the biggest question is how you want to “communicate” with this headless instance of Rhino. Compute.geometry is basically setup to communicate over REST API calls. It’s easy to setup and any “client” that can send GET/POST requests can essentially communicate with it. But, if instead you plan to keep all communication internal to your app, then using something more like Rhino.Inside might be preferrable. If you would prefer to use Rhino.Iniside, I may want to bring in my colleague @kike as he has more experience in that domain.

My preferred approach is to keep everything internal within my application.

However, I’ve already attempted to refactor my code using Rhino.Inside, but I encountered issues when trying to run multiple instances of my process simultaneously, as I previously described in this same thread:

:link: Managing Multiple Rhino 8 Instances in Headless Mode

When launching a single instance, everything works fine. The problem arises when multiple instances are started simultaneously, whether via PowerShell or the Windows Service queue process, at which errors occur.

Would you recommend an alternative approach to handle multiple concurrent instances reliably?