Site Tools


Create a Skin using the Rhino C++ SDK

Developer: C++
Summary: The Rhino Application Platform (RAP) provides the tools for C++ developers to wrap their application around Rhino by creating a custom Skin.

Overview

Rhino allows developers to customize most of Rhino's interface so that the application appears to be their own. We call this a custom Skin. With a custom Skin, you can change the application icon, splash screen, the menu bar, the application title bar, the about box, and the toolbars.

Creating a custom Skin for Rhino involves creating two code modules:

  • <skin name>.rhs is a regular MFC DLL that implements the skin's icon, splash screen, and, optionally, a menu. In this article, we will refer this to the Skin DLL.
  • <skin name>.rhp is a Rhino utility plug-in that implements the menu handler, if necessary, and one or more custom commands. In this article, we will refer to this as the Skin Plug-in.

Create the Skin DLL

  • A Skin DLL is a regular MFC DLL that implements the skin's icon, splash screen, and, optionally, a menu.
  • To create the Skin DLL, launch Visual Studio and run the Rhino Skin DLL wizard installed by the Rhino SDK.
  • The Rhino Skin DLL wizard will create three classes:
    1. A CWinApp-derived class. This is the entry point of the DLL.
    2. A CRhinoSkinDLL-derived class. This class allows you to specify Rhino's icon, splash screen and menu. For more information on this class, see rhinoSdkSkinDLL.h.
    3. CSplashWnd. This is a basic implementation of a splash screen class. If you require something fancier, feel free to replace it with your own implementation.
  • Modify the project's icon and splash screen bitmap. If your Skin is going to override Rhino's main menu, then you will need to create your menu resources as well.
  • Do not forget to fill out the developer information block found at the top of your DLL's .CPP file. This block is similar to that of Rhino plug-ins.

Create the Skin Plug-in

  • A Skin Plug-in is a Rhino utility plug-in that implements the menu handler, if necessary, and one or more custom commands.
  • To create a Rhino utility plug-in, launch Visual Studio and run the Rhino Plug-in wizard installed by the Rhino SDK. When picking the wizard to run, make sure to add the new project to the open solution instead of creating a new solution. This way, your Skin project will be origanized into a single solution.
  • If the Skin DLL provides a custom menu, then copy the UUID generated by the plug-in AppWizard and found in your plug-in's CRhinoPlugIn::PlugInID() member to your Skin's CRhinoSkinDLL::SkinPlugInID() member.
  • Important! These two methods must return the same UUID. This is a critical step as it identifies the main plug-in that Rhino will load to manage its menus and extend the Rhino command set.
  • Add the following overrides to the header file of your CRhinoPlugIn-derived class:
// Skin DLL menu update handler
void OnInitPlugInMenuPopups(WPARAM wparam, LPARAM lparam);
 
// Skin DLL menu command handler
BOOL OnPlugInMenuCommand(WPARAM wparam );
 
// Change to CRhinoPlugIn::load_plugin_at_startup
plugin_load_time PlugInLoadTime();
  • Add the following definition to the .CPP file of your CRhinoPlugIn-derived class.
CRhinoPlugIn::plugin_load_time CSkinPlugInSamplePlugIn::PlugInLoadTime()
{
  // Override to change load time to "at startup"
  return CRhinoPlugIn::load_plugin_at_startup;
}
  • If your Skin DLL is providing a custom menu, then add a source file named MenuHandler.cpp to the plug-in project and put the definition of CRhinoPlugIn::OnInitPlugInMenuPopups() and CRhinoPlugIn::OnPlugInMenuCommand() in this file.
  • Important! Include the Skin DLL's Resource.h file in MenuHandler.cpp to provide access to the Skin DLL's menu resource identifiers. For example:
#include "stdafx.h"
#include "MySkinPlugIn.h"
#include "../MySkinDLL/Resource.h"
 
// Put these to overrides in a separate CPP file so they could
// include the MySkinDLL/Resource.h file without conflicting
// with this projects resource.h
 
void CSkinPlugInSamplePlugIn::OnInitPlugInMenuPopups(WPARAM wParam, LPARAM lParam)
{
  HMENU hMenu = (HMENU)wParam;
  if( NULL == hMenu )
    return;
 
  switch( GetMenuItemID(hMenu, LOWORD(lParam)) )
  {
    case IDM_SAMPLE_DISABLE:
      ::EnableMenuItem( hMenu, IDM_SAMPLE_DISABLE, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED );
      break;
    case IDM_SAMPLE_SUB_DISABLE:
      ::EnableMenuItem( hMenu, IDM_SAMPLE_SUB_DISABLE, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED );
      break;
    // TODO...
  }
}
 
BOOL CSkinPlugInSamplePlugIn::OnPlugInMenuCommand(WPARAM wParam)
{
  ON_wString w;
  switch( (UINT)wParam )
  {
    case IDM_SAMPLE_ONE:
      w = L"Test Item One";
      break;
    case IDM_SAMPLE_TWO:
      w = L"Two";
      break;
    case IDM_SAMPLE_DISABLE:
      w = L"Disabled";
      break;
    case IDM_SAMPLE_SUB_A:
      w = L"Sub Menu A";
      break;
    case IDM_SAMPLE_SUB_B:
      w = L"Sub Menu B";
      break;
    case IDM_SAMPLE_SUB_DISABLE:
      w = L"Sub Menu Disabled";
      break;
    default:
      return true;
  }
 
  ::RhinoMessageBox( w, L"OnMenu", MB_OK );
  return true;
}

Finishing Up

  • Compile the Skin Plug-in.
  • Load the Skin Plug-in using Rhino's PluginManager command so it has a chance to self-register.
  • Compile the Skin DLL.

Installation

To install your custom Skin, use REGEDIT.EXE to add a scheme key to your registry with a path to your Skin DLL. For example:

ItemValue
SubkeyHKEY_LOCAL_MACHINE\SOFTWARE\McNeel\Rhinoceros\4.0\Scheme: MySkin
Entry nameSkinDLLPath
TypeREG_SZ
Data valueC:\Src\MySkin\MySkinDLL\Release\MySkinDLL.rhs

You can now test your custom Skin by creating shortcut to your Rhino executable with /scheme=”<scheme name from the previous step>” as command line argument. For example:

"C:\Program Files\Rhinoceros 4.0\System\Rhino4.exe" /scheme=MySkin

Additional Information

If the user chooses not to run your skinned version of Rhino, you might want to prevent your skin plug-in loading. You can do this by checking to see if the name of the scheme, that Rhino is using, matches your skin's scheme name. Do this checking in your plug-in's CRhinoPlugIn::OnLoadPlugIn() member.

For example:

BOOL CSkinPlugInSamplePlugIn::OnLoadPlugIn()
{
  ON_wString scheme = RhinoApp().RegistrySchemeName();
  if( scheme.CompareNoCase(L"Scheme: MySkin") != 0 )
    return -1; // Fail silently...
 
  // TODO...
 
  return CRhinoUtilityPlugIn::OnLoadPlugIn();
}


developer/sdksamples/skin.txt · Last modified: 2014/01/23 (external edit)