Site Tools


Differences

This shows you the differences between two versions of the page.

Link to this comparison view

developer:runrhinocommandfromplugincommand [2015/09/14] (current)
Line 1: Line 1:
 +======How to run a Rhino command from a plug-in command======
 +> **Developer:​** //​[[developer:​cplusplusplugins|C++]],​ [[developer:​dotnetplugins|.NET]],​ [[developer:​rhinocommon|RhinoCommon]]//​
 +> **Summary:​** //Discusses the proper techniques to use when running a 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 commands except under very special circumstances.
 +
 +//​Here'​s the issue: //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:
 +
 +<code c++>
 +class CCommandTest : public CRhinoCommand
 +</​code>​
 +
 +Define your command class like this:
 +
 +<code c++>
 +class CCommandTest : public CRhinoScriptCommand
 +</​code>​
 +
 +Then, from within your command class'​s **RunCommand()** member, you can call **CRhinoApp::​RunScript()** to script the running of a Rhino command. For example.
 +
 +<code c++>
 +CRhinoCommand::​result CCommandTest::​RunCommand( const CRhinoCommandContext&​ context )
 +{
 +  RhinoApp().RunScript( L"​_-Line 0,0,0 10,​10,​10",​ 0 );
 +  return CRhinoCommand::​success;​
 +}
 +</​code>​
 +
 +\\
 +
 +=====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#====
 +<code c#>
 +[System.Runtime.InteropServices.Guid(<<​test_command_guid>>​)]
 +public class TestCommand : Rhino.Commands.Command
 +</​code>​
 +
 +====VB====
 +<code vb>
 +<​System.Runtime.InteropServices.Guid(<<​test_command_guid>>​)>​ _
 +Public Class TestCommand
 +  Inherits Rhino.Commands.Command
 +</​code>​
 +
 +Define your command classes like this:
 +
 +====C#====
 +<code c#>
 +
 + ​System.Runtime.InteropServices.Guid(<<​test_command_guid>>​), ​
 + ​Rhino.Commands.CommandStyle(Rhino.Commands.Style.ScriptRunner)
 +]
 +public class TestCommand : Rhino.Commands.Command
 +</​code>​
 +
 +====VB====
 +<code vb>
 +< _
 +  System.Runtime.InteropServices.Guid(<<​test_command_guid>>​),​ _
 +  Rhino.Commands.CommandStyle(Rhino.Commands.Style.ScriptRunner) _
 +> _
 +Public Class TestCommand
 +  Inherits Rhino.Commands.Command
 +</​code>​
 +
 +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#====
 +<code 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;​
 +}
 +</​code>​
 +====VB====
 +<code 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
 +</​code>​
 +
 +\\
 +
 +=====Rhino.NET SDK=====
 +----
 +Inherit your command class from **MRhinoScriptCommand** instead of **MRhinoCommand**. In other words, instead of defining your command classes like this:
 +
 +====C#====
 +<code c#>
 +public class TestCommand : RMA.Rhino.MRhinoCommand
 +</​code>​
 +
 +====VB====
 +<code vb>
 +Public Class TestCommand
 +  Inherits RMA.Rhino.MRhinoCommand
 +</​code>​
 +
 +Define your command classes like this:
 +
 +====C#====
 +<code c#>
 +public class TestCommand : RMA.Rhino.MRhinoScriptCommand
 +</​code>​
 +
 +====VB====
 +<code vb>
 +Public Class TestCommand
 +  Inherits RMA.Rhino.MRhinoScriptCommand
 +</​code>​
 +
 +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#====
 +<code c#>
 +public override IRhinoCommand.result RunCommand(IRhinoCommandContext context)
 +{
 +  RhUtil.RhinoApp().RunScript("​_-Line 0,0,0 10,​10,​10",​ 0);
 +  return IRhinoCommand.result.success;​
 +}
 +</​code>​
 +
 +====VB====
 +<code 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
 +</​code>​
 +
 +\\
 +
 +=====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:
 +
 +  - If you are not very familiar with how C++ references work, you should only call CRhinoApp::​RunScript() from within a CRhinoScriptCommand derived command.
 +  - If you are very familiar with C++ references, then please observe the following rules:
 +    - 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().
 +    - If you get a reference or a pointer, then call CRhinoApp::​RunScript(),​ and then use the reference, Rhino will probably crash.
 +    - 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++====
 +<code 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;​
 +}
 +</​code>​
 +
 +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.
 +
 +\\
 +
 +{{tag>​Developer cplusplus dotnet rhinocommon}}
developer/runrhinocommandfromplugincommand.txt ยท Last modified: 2015/09/14 (external edit)