Your First Plugin (Windows)
Windows only

It is presumed you already have the necessary tools installed and are ready to go. If you are not there yet, see Installing Tools (Windows).

Barebones plugin

We will use the RhinoCommon Plugin for Rhino 3D (C#) project template to create a new general purpose plugin. The project template generates the code for a functioning plugin. Follow these steps to build the plugin.

Plugin Template

  1. Launch Visual Studio and navigate to File > New > Project….

  2. From the Create a new project dialog, select the RhinoCommon Plugin for Rhino 3D (C#) template from the list of installed templates and click Next.

    New Project Template

  3. Type the project name as shown below. You can enter a different name if you want. The template uses the project name when it creates files and classes. If you enter a different name, your files and classes will have a name different from that of the files and classes mentioned in this tutorial. Don’t forget to choose a location to store the project. When finished, click Create.

    New Project Configure

  4. Upon clicking Create, the New Rhino C++ Plugin dialog will appear. By default, the template will create a General Utility plugin.

    Plugin Settings

  5. The New RhinoCommon .NET Plugin dialog allows you to modify a number of settings used by the template when generating the plugin source code:

    1. Plugin name: Modify this field if you want to change the name of the plugin’s class name.
    2. Command class name:: Modify this field if you want to change the name of the plugin’s initial command class name.
    3. Plugin type: Select the type of plugin that you want the template to create.
    4. Target Version: Select the target Rhino version.
    5. Wndows UI: If you are planning on using Windows Forms or WPF for user interface, instead of Eto, then check the approprate box.
    6. Rhino location: Modify this field if the path to Rhino.exe is found in a different location than what is shown.
  6. For this tutorial, just accept the default settings. Click the Finish button, and the template begins to generate your plugin project’s folders, files, and classes. When the template is finished, look through the plugin project using Visual Studio’s Solution Explorer

Plugin Anatomy

Use the Solution Explorer to expand the Solution (.sln) so that it looks like this.

Plugin Anatomy

  1. HelloRhinoCommon: The plugin project (.csproj), which has the same name as its parent solution. The project that was created for us by the project template we just used.
  2. Dependencies: Contains references to both the .NET Framework 4.8 and .NET 7.0 assemblies required by the plugin. The project obtains RhinoCommon dependencies via NuGet.
  3. Properties: Contains the AssemblyInfo.cs source file. This file contains the meta-data, such as author and copyright, that appears in Rhino’s Plugin Manager.
  4. Embedded Resources: Contains icons, bitmaps, and other non-code resources you want embedded in your plugin.
  5. HelloRhinoCommonCommand.cs: The initial plugin command, which inherits from Rhino.Commands.Command.
  6. HelloRhinoCommonPlugin.cs: The plugin class, which inherits from Rhino.Plugins.Plugin.

Testing

  1. From Visual Studio, navigate to Debug > Start Debugging. You can also press F5, or click the Debug button on Visual Studio’s toolbar. This will load Rhino.

  2. From within Rhino, navigate to Tools > Options. Navigate to the Plugins page under Rhino Options and install your plugin.

    Rhino Options

  3. Once your plugin is loaded, close the options dialog and run your HelloRhinoCommonCommand command.

  4. You have finished creating your first plugin!

Adding Additional Commands

Rhino plugins can contain any number of commands. Commands are created by inheriting a new class from Rhino.Commands.Command.

Note, Command classes must return a unique command name. If you try to use a command name that is already in use, then your command will not work.

To add a new Rhino command to your plugin project, right-click on the project, in Visual Studio’s Solution Explorer, and click Add > New Item…. From the Add New Item dialog, select Empty RhinoCommon Command for Rhino 3D (C++), specify the name of the command, and click Add.

Rhino Command

Example

The following example code demonstrates a simple command class that essentially does nothing:

using Rhino;
using Rhino.Commands;
using Rhino.Geometry;
using Rhino.Input;
using Rhino.Input.Custom;

namespace HelloRhinoCommon
{
  public class HelloRhinoCommonCommand : Command
  {
    public HelloRhinoCommonCommand()
    {
      // Rhino only creates one instance of each command class defined in a
      // plug-in, so it is safe to store a refence in a static property.
      Instance = this;
    }

    ///<summary>The only instance of this command.</summary>
    public static HelloRhinoCommonCommand Instance { get; private set; }

    ///<returns>The command name as it appears on the Rhino command line.</returns>
    public override string EnglishName => "HelloRhinoCommonCommand";

    protected override Result RunCommand(RhinoDoc doc, RunMode mode)
    {
      // TODO: start here modifying the behaviour of your command.
      // ---
      RhinoApp.WriteLine("The {0} command will add a line right now.", EnglishName);

      Point3d pt0;
      using (GetPoint getPointAction = new GetPoint())
      {
        getPointAction.SetCommandPrompt("Please select the start point");
        if (getPointAction.Get() != GetResult.Point)
        {
          RhinoApp.WriteLine("No start point was selected.");
          return getPointAction.CommandResult();
        }
        pt0 = getPointAction.Point();
      }

      Point3d pt1;
      using (GetPoint getPointAction = new GetPoint())
      {
        getPointAction.SetCommandPrompt("Please select the end point");
        getPointAction.SetBasePoint(pt0, true);
        getPointAction.DynamicDraw +=
          (sender, e) => e.Display.DrawLine(pt0, e.CurrentPoint, System.Drawing.Color.DarkRed);
        if (getPointAction.Get() != GetResult.Point)
        {
          RhinoApp.WriteLine("No end point was selected.");
          return getPointAction.CommandResult();
        }
        pt1 = getPointAction.Point();
      }

      doc.Objects.AddLine(pt0, pt1);
      doc.Views.Redraw();
      RhinoApp.WriteLine("The {0} command added one line to the document.", EnglishName);

      // ---
      return Result.Success;
    }
  }
}