Site Tools


How to run a Rhino command from a plug-in command

Developer: C++, .NET, RhinoCommon
Summary: Discusses the proper techniques to use when running Rhino command from within the context of a plug-in command.

One of the most common questions asked by new plug-in developers is how to run, or script, existing Rhino commands from a plug-in command. Rhino doesn't allow plug-in commands to run other command except under very special circumstances.

Here's the problem: If you have a command that is modifying the run-time database, and you run another command, problems can happen.

To work around this, the Rhino SDK provides a special kind of command called a script command. You can create a script command as follows:

Rhino C++ SDK


Derive your command class from CRhinoScriptCommand instead of CRhinoCommand. In other words, instead of defining your command class like this:

class CCommandTest : public CRhinoCommand

Define your command class like this:

class CCommandTest : public CRhinoScriptCommand

Then, from within your command class's RunCommand() member, you can call CRhinoApp::RunScript() to script the running of a Rhino command. For example.

CRhinoCommand::result CCommandTest::RunCommand( const CRhinoCommandContext& context )
{
  RhinoApp().RunScript( L"_-Line 0,0,0 10,10,10", 0 );
  return CRhinoCommand::success;
}


RhinoCommon


When defining your command class, make sure to add the ScriptRunner command style attribute. In other words, instead of defining your command classes like this:

C#

[System.Runtime.InteropServices.Guid(<<test_command_guid>>)]
public class TestCommand : Rhino.Commands.Command

VB

<System.Runtime.InteropServices.Guid(<<test_command_guid>>)> _
Public Class TestCommand
  Inherits Rhino.Commands.Command

Define your command classes like this:

C#

[ 
 System.Runtime.InteropServices.Guid(<<test_command_guid>>), 
 Rhino.Commands.CommandStyle(Rhino.Commands.Style.ScriptRunner)
]
public class TestCommand : Rhino.Commands.Command

VB

< _
  System.Runtime.InteropServices.Guid(<<test_command_guid>>), _
  Rhino.Commands.CommandStyle(Rhino.Commands.Style.ScriptRunner) _
> _
Public Class TestCommand
  Inherits Rhino.Commands.Command

Then, from within your command class's RunCommand() member, you can call RhinoApp.RunScript() to script the running of a Rhino command. For example.

C#

protected override Rhino.Commands.Result RunCommand(Rhino.RhinoDoc doc, Rhino.Commands.RunMode mode)
{
  Rhino.RhinoApp.RunScript("_-Line 0,0,0 10,10,10", false);
  return Rhino.Commands.Result.Success;
}

VB

Protected Overrides Function RunCommand(ByVal doc As Rhino.RhinoDoc, ByVal mode As Rhino.Commands.RunMode) As Rhino.Commands.Result
  Rhino.RhinoApp.RunScript("_-Line 0,0,0 10,10,10", False)
  Return Rhino.Commands.Result.Success
End Function


Rhino.NET SDK


Inherit your command class from MRhinoScriptCommand instead of MRhinoCommand. In other words, instead of defining your command classes like this:

C#

public class TestCommand : RMA.Rhino.MRhinoCommand

VB

Public Class TestCommand
  Inherits RMA.Rhino.MRhinoCommand

Define your command classes like this:

C#

public class TestCommand : RMA.Rhino.MRhinoScriptCommand

VB

Public Class TestCommand
  Inherits RMA.Rhino.MRhinoScriptCommand

Then, from within your command class's RunCommand() member, you can call MRhinoApp.RunScript() to script the running of a Rhino command. For example.

C#

public override IRhinoCommand.result RunCommand(IRhinoCommandContext context)
{
  RhUtil.RhinoApp().RunScript("_-Line 0,0,0 10,10,10", 0);
  return IRhinoCommand.result.success;
}

VB

Public Overrides Function RunCommand(ByVal context As RMA.Rhino.IRhinoCommandContext) As RMA.Rhino.IRhinoCommand.result
  RhUtil.RhinoApp().RunScript("_-Line 0,0,0 10,10,10", 0)
  Return IRhinoCommand.result.success
End Function


More Information


Note, this section specifically mentions the Rhino C++ SDK. But, the information also applies to Rhino.NET and RhinoCommon.

This kind of command can be very dangerous. Please be sure you understand the following:

  1. If you are not very familiar with how C++ references work, you should only call CRhinoApp::RunScript() from within a CRhinoScriptCommand derived command.
  2. If you are very familiar with C++ references, then please observe the following rules:
    1. If you get a reference or pointer to any part of the Rhino run-time database, this reference or pointer will not be valid after you call CRhinoApp::RunScript().
    2. If you get a reference or a pointer, then call CRhinoApp::RunScript(), and then use the reference, Rhino will probably crash.
    3. All pointers and references used by the command should be scoped such that they are only valid for the time between calls to CRhinoApp::RunScript().

This is because CRhinoApp::RunScript() can change the dynamic arrays in the run-time database. The result is that all pointers and references become invalid. Be sure to scope your variables between CRhinoApp::RunScript() calls.

Example

Here's good scoping practice when your command is a script command.

C++

CRhinoCommand::result CCommandTest::RunCommand( const CRhinoCommandContext& context )
{
  {
    section A
    ... do some stuff ...
  }
  RhinoApp().RunScript(...);
  {
    section B
    ... do some stuff ...
  }
  RhinoApp().RunScript(...);
  {
    section C
    ... do some stuff ...
  }
  RhinoApp().RunScript(...);
  {
    section D
    ... do some stuff ...
  }
  RhinoApp().RunScript(...);
  {
    section E
    ... do some stuff ...
  }
  return CRhinoCommand::success;
}

Never allow references and pointers from one section to be used in another section.

Downsides

In a normal command, when the user enters a command beginning with a !, the command exits. There is no documented way to get this behavior from within a script command.


developer/runrhinocommandfromplugincommand.txt ยท Last modified: 2014/01/23 (external edit)