Rhino Application Platform (RAP)
Summary: The Rhino Application Platform (RAP) provides the tools for C++ developers to wrap their application around Rhino 4.0 by creating a custom “Skin”.
Overview
Rhino 4.0 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 .NET 2005 and run the Rhino Skin AppWizard installed by the Rhino SDK.
- The Rhino Skin AppWizard will create three classes:
- A CWinApp-derived class. This is the entry point of the DLL.
- 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.
- 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 .NET 2005 and run the Rhino Plug-in AppWizard installed by the Rhino SDK. When picking the AppWizard 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 OnInitPlugInMenuPopups() and 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:
| Item | Value |
| Subkey | HKEY_LOCAL_MACHINE\SOFTWARE\McNeel\Rhinoceros\4.0\Scheme: MySkin |
| Entry name | SkinDLLPath |
| Type | REG_SZ |
| Data value | C:\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
Question One
If the user chooses not to run my “skinned” version of Rhino, how can I keep my skin-specific plug-in from loading?
Answer
In your plug-in's OnLoadPlugIn member, check to see if the name of the scheme that Rhino is using matches your skin's scheme name. For example:
BOOL CSkinPlugInSamplePlugIn::OnLoadPlugIn() { ON_wString scheme = RhinoApp().RegistrySchemeName(); if( scheme.CompareNoCase(L"Scheme: MySkin") != 0 ) return -1; // Fail silently... return CRhinoUtilityPlugIn::OnLoadPlugIn(); }
