McNeel Wiki
Adding RhinoScript support to Rhino Plug-ins
edit · print · help · all topics
Main Pages

AccuRender

Bongo

Brazil r/s

Developer

Flamingo

Penguin

Rhino Blogs

Rhino

Search

Languages

Česky

Deutsch

English

Español

Français

Italiano

Polish

日本語

한국어

中文(繁體)

 
.
DeveloperC++
VersionRhino 4
SummaryDemonstrates how to add RhinoScript support to C++ plug-ins.

Note for .NET developers

The .NET equivalent to this article can be found at SdkExtendRhinoScript

Overview

With the Rhino 4.0 SDK, it is now possible to write plug-ins that extend the RhinoScript scripting tool. In order to do this, a plug-in must do the following:

  1. Create a COM object that implements the IDispatch interface.
  2. Override the CRhinoPlugIn::GetPlugInObjectInterface() to give plug-ins, such as RhinoScript, access to this object.

Example

In the following example, we will create a new plug-in named TestScript that support RhinoScript scripting. If you are familar with creating C++ projects that support COM automation and you just want to review the sample plug-in source code, then you can download it here.

Also, the purpose of this example is not to teach COM Automation or to explain how the .IDL file work or what Variants are. There is plenty of information in MSDN and on the Internet that explain these areas.

Step 1: Create a plug-in that support Automation

Launch Visual C++ 2005 and create a new Rhino Plug-in project named TestScript. On the Plug-in Settings page of the Rhino Plug-in Appwizard dialog box, make sure to check the Automation check box. One the Appwizard has completed creating the skeleton project, build the project.

Step 2: Create a COM object that supports IDispatch

Create a new MFC class by running the MFC Class Wizard. Name the class CTestScriptObject. This class should be derived from CCmdTarget. Also, under Automation, select the Automation radio button. Note, this COM object will not be creatable by type ID because Rhino plug-ins (DLLs) are dependent on Rhino.

Step 3: Add methods to your object

An object is not useful unless you expose methods or properties. In this example, we will create a new method that allows the scripter to add point objects to Rhino. Within Class View, select your new object's interface and add a new method using the Add Method Wizard. Give the new method the name of AddPoint. It should have a single VARIANT* argument and return a VARIANT.

Step 3: Implement your methods

The Add Method Wizard will create a placeholder for our AddPoint method in TestScriptObject.cpp. Add the following code to your new method:

  VARIANT CTestScriptObject::AddPoint(VARIANT* vaPoint)
  {
    VARIANT vaResult;
    VariantInit(&vaResult);
    V_VT(&vaResult) = VT_NULL;


    if( vaPoint )
    {
      ON_3dPoint pt;
      if( VariantToPoint(*vaPoint, pt) )
      {
        CRhinoDoc* doc = RhinoApp().ActiveDoc();
        if( doc )
        {
          CRhinoPointObject* obj = doc->AddPointObject( pt );
          if( obj )
          {
            doc->Redraw();
            ON_wString wstr;
            ON_UuidToString( obj->Attributes().m_uuid, wstr );
            CString str(wstr);
            V_VT(&vaResult) = VT_BSTR;
            vaResult.bstrVal = str.AllocSysString();
          }
        }
      }
    }


    return vaResult;
  }

In the above code, the VARIANT* argument is converted to an ON_3dPoint using the VariantToPoint() function. One of the biggest challenges to creating RhinoScript accessable objects is converting the COM Variant data type to an openNURBS data type and back. Fortunately, I have done all of the work for you. The sample project mention above includes a number of utility function to help you convert Variant data type to a number of openNURBS data types. There are also a number of function to do just the opposite. Just look for the VariantUtilities.h/cpp files.

Once the Variant has been converted to an ON_3dPoint, the code simply adds the point to Rhino. But, just like RhinoScript's AddPoint method, this method also returns the object's unique identifer.

Step 4: Allow access to your object

Now that you have a COM object that implements IDispatch and has at least one method, we can allow access to it. The easiest way is to put a copy of your new COM object on your plug-in object as a data member. For example:

  class CTestScriptPlugIn : public CRhinoUtilityPlugIn
  {
  public:
    CTestScriptPlugIn();
    ~CTestScriptPlugIn();


    // Required overrides
    const wchar_t* PlugInName() const;
    const wchar_t* PlugInVersion() const;
    GUID PlugInID() const;
    BOOL OnLoadPlugIn();
    void OnUnloadPlugIn();


    // Optional overrides
    LPUNKNOWN GetPlugInObjectInterface( const ON_UUID& iid );


  private:
    ON_wString m_plugin_version;
    CTestScriptObject m_object;
  };

Then, allow access to the object by overriding the GetPlugInObjectInterface() virtual function. For example:

  LPUNKNOWN CTestScriptPlugIn::GetPlugInObjectInterface( const ON_UUID& iid )
  {
    LPUNKNOWN lpUnknown = 0;


    if( iid == IID_IUnknown )
      lpUnknown = m_object.GetInterface( &IID_IUnknown );


    else if( iid == IID_IDispatch )
      lpUnknown = m_object.GetInterface( &IID_IDispatch );


     if( lpUnknown )
      m_object.ExternalAddRef();


    return lpUnknown;
  }

Note, RhinoScript will only request an IDispatch object from your plug-in. Also because our object is a data member of our plug-in object, we must increment our object's reference counter. Otherwise, when ""VBScript" releases our object, which will decrement the reference counter, our object will be destroyed. This will cause your plug-in to crash.

Step 5: Implement your methods

Once you have implemented your methods, you can begin to test them. Launch Rhino and use the PlugInManager command to install your new plug-in. Then, use RhinoScript's EditScript dialog to test the methods in your plug-in's object.

The following code demonstrates how to get our plug-ins scriptable object and run the AddPoint method.

rename · changes · history · subscriptions · lost and found · references · file upload