In this post, we continue our review of the Windows Ribbon Framework feature brought to us in Windows 7. For more information on the ribbon feature in general and the Windows Ribbon Framework in particular, make sure you read Part 1.
Today we will see how to create a ribbon enabled application in C++ using the Windows Ribbon Framework. To show it, we will build a small application with a ribbon that will contain two tabs, three groups, and several buttons.
As mentioned in the previous post, there are four steps we need to follow in order to create a ribbon enabled application. Let's dive into the details of these steps.
One last note before we start, this post requires knowledge in both Win32 and COM development. Also, if you wish to compile the sample application attached to this post, make sure you have Windows 7 SDK installed.
Step 1: Define the Ribbon UI
The first thing to do is to declare the ribbon user interface. This is done by creating an XML file that will contain the ribbon UI definition using a XAML-based syntax.
For our demo application, let's create a file named RibbonMarkup.xml (the XML suffix is not mandatory but is still recommended), with the following content:
TooltipDescription="Create a new image.">
TooltipDescription="Open an existing image.">
TooltipDescription="Save the current image.">
LabelDescription="Sub button A">
LabelDescription="Sub button B">
LabelDescription="Sub button C">
<Group CommandName="cmdGroupFileActions" SizeDefinition="ThreeButtons">
<Button CommandName="cmdButtonNew" />
<Button CommandName="cmdButtonOpen" />
<Button CommandName="cmdButtonSave" />
<Group CommandName="cmdGroupExit" SizeDefinition="OneButton">
<Button CommandName="cmdButtonExit" />
<Tab CommandName ="cmdTabMore">
<Group CommandName="cmdGroupMore" SizeDefinition="ThreeButtons">
<Button CommandName="cmdButtonMoreA" />
<Button CommandName="cmdButtonMoreB" />
<Button CommandName="cmdButtonMoreC" />
OK, this may look intimidating at first glance, but it is rather easy to understand. The ribbon UI definition file has two major sections,
For now, suffice to say that the
Commands section defines the different actions a user can invoke using the ribbon UI controls. Each such command is defined with its required resources (strings and images). Later, we will write command handlers in the application code.
Views section defines the UI controls we want to use and their layout in the ribbon. Each UI control is bound to a command and thus will trigger it when the UI control executes (e.g., button clicked).
More details on the
Views sections will be reviewed on the next post.
A look on the
Views section reveals that in our demo application the ribbon has two tabs; the first tab has two groups and the second tab contains one group. Each group contains some buttons. In other words:
Figure 1: First tab
Figure 2: Second tab
If you try to follow the steps yourself, make sure the images you use are bitmaps (BMP format) that have 32 bits per pixel (32BPP). This is a mandatory need for all images used with the Windows Ribbon Framework.
Step 2: Compile the Ribbon UI
In this step, we will see how to use the Ribbon Markup Compiler provided with the Windows 7 SDK to compile the ribbon markup that we wrote in the previous step into a compact binary representation of the ribbon UI.
The compiler executable name is UICC.exe and it can be found at:
To manually compile the markup, open the Windows SDK "CMD Shell" and run:
UICC.exe RibbonMarkup.xml RibbonUI.bml /header:RibbonIDs.h /res:RibbonResource.rc
UICC does the following upon run:
- Validates the ribbon markup syntax.
- Generates a compressed binary representation of the markup along with an RC file that describes it. In our demo, these are the files RibbonUI.bml and RibbonResource.rc, respectively.
- Generates a C++ header file containing constants for the ribbon identifiers. This will be proved useful when we we'll implement the command handlers. In our demo, it is the file RibbonIDs.h.
Note that since our ribbon markup is rather light, the compiler will generate warnings about some missing markup elements. These warnings are not important at this point and we can safely ignore them.
Later, in step 4, we will setup the ribbon markup compilation as a custom build event in our project.
Step 3: Write Command Handlers Code
In this step, we will see how to write code that initializes the Windows Ribbon Framework, loads the previously compiled ribbon UI, and respond to events generated by the ribbon UI controls.
Before we dive into the code, let's get to know the main players participating in a ribbon enabled application, namely: UIRibbonFramework, IUIApplication and IUICommandHandler.
UIRibbonFramework is a COM class provided by the Windows Ribbon Framework, which implements the
IUIFramework interface. This class is the entry point to the Windows Ribbon Framework. It provides functions for both initializing and destroying the ribbon framework within your application as well as other functions to control the ribbon behavior.
Its most important functions are:
Initialize(HWND topWindow, IUIApplication* application)
This function initializes the Windows Ribbon Framework within your application. It receives an
IUIApplication interface which we should implement to supply callbacks that the ribbon framework will invoke. More on this interface later.</li />
LoadUI (HINSTANCE instance, LPCWSTR resourceName)
This function loads the ribbon UI resource. After this function gets called, the ribbon control should be visible.
This function releases all the object references held by the Windows Ribbon Framework.
As mentioned before,
IUIApplication is an interface that our application should implement. It provides three callbacks that the ribbon framework will invoke when needed.
OnCreateUICommand(UINT32 commandId, UI_COMMANDTYPE typeId, IUICommandHandler** commandHandler)
This function is called by the ribbon framework when a command, defined in the ribbon markup, should bind to a command handler. The
IUICommandHandler is yet another interface we should implement to handle commands execution. More on this interface later.
OnDestroyUICommand(UINT32 commandId, UI_COMMANDTYPE typeId, IUICommandHandler* commandHandler)
This function is called by the ribbon framework when the application window gets destroyed for each command defined in the ribbon markup.
OnViewChanged(UINT32 viewId, UI_VIEWTYPE typeId, IUnknown* view, UI_VIEWVERB verb, INT32 uReasonCode)
This function is called by the ribbon framework when the ribbon view has changed. For example, when the ribbon is resized, created, or destroyed.</li />
IUICommandHandler interface should also be implemented by our application. It is used to execute our code in response to user actions on the ribbon UI controls. You can think of it as the place to write your "
This interface provides two callbacks that the ribbon framework will invoke when needed:
Execute(UINT32 commandId, UI_EXECUTIONVERB verb, const PROPERTYKEY* key, const PROPVARIANT* currentValue, IUISimplePropertySet* commandExecutionProperties)
This function is called by the ribbon framework when the user performs an action on a UI control which is bound to the command identified by the
commandId parameter. An example for such an action is clicking a button or selecting an item in a combobox.
UpdateProperty(UINT32 commandId, REFPROPERTYKEY key, const PROPVARIANT* currentValue, PROPVARIANT* newValue)
This function is called by the ribbon framework when it needs to know the value of a property of a UI control which is bound to the command identified by the
commandId parameter. This can be used to update properties that change dynamically, like the items list in a combobox control or the enabled state of a button.
Initializing the Ribbon
Now that we are familiar with the main players, we can better understand the flow of a ribbon enabled application.
To initialize the ribbon in your application, do the following:
- On application load, call
UIRibbonFramework class implements the
IUIFramework::Initialize and pass it a reference to your implementation of the
IUIApplication interface along with the
HWND of your application window.
IUIFramework::LoadUI which loads the pre-compiled resource and shows the real ribbon.
The following code shows how to initialize the ribbon framework; it should be called when the application loads. A good place would be when handling the message
Note: error handling code was removed for clarity.
IUIApplication. The important part of it is to supply the implementation of
IUICommandHandler when asked by the ribbon framework. This is done by implementing
IUIApplication::OnCreateUICommand as follows:
if (NULL == m_pCommandHandler)
Note that our implementation of
IUIApplication returns the same
CCommandHandler object regardless of the command ID. Since the
IUICommandHandler::Execute function receives the executing command ID, we can avoid creating a separate command handler class for each command.
The following diagram (from MSDN) shows the interactions between the different components when initializing a ribbon enabled application:
Figure 3: Initializing a ribbon enabled application
Implementing Command Handlers
In order to respond to user actions on the ribbon, we must implement
const PROPERTYKEY* key,
const PROPVARIANT* ppropvarValue,
HWND hwnd = GetForegroundWindow();
MessageBox(hwnd, L"New button was clicked", L"New Clicked", 0);
PostMessage(hwnd, WM_CLOSE, NULL, NULL);
In this example, we respond to the "New" button click event and present a message box. We respond to the "Exit" button click event by posting the
You might be asking yourself who declared the
ID_CMD_EXIT constants (and if not, you should!). Well, if you recall, in step 2, one of the products of the ribbon markup compiler was a RibbonIDs.h file. This file contains exactly those constants. The name of the constant is what we have defined in the
Symbol attribute of the command element, in the ribbon markup. The value of the constant is auto-generated, but can be manually specified by using the
Id attribute in the ribbon markup.
Note that it is critical to use
PostMessage and not
SendMessage, otherwise the application will crash when closing using this exit command. This is a classic case of cutting the branch you sit on. The reason for the crash when using
SendMessage is that the handling of
IUIFramework::Destroy() which releases all the COM objects used by the ribbon framework, including
CCommandHandler. Since the
CCommandHandler is still in use (we called
CCommandHandler::Execute), we get a memory corruption.
The following diagram (from MSDN) shows the interactions between the different components when the user interacts with the ribbon control:
Figure 4: Ribbon framework interaction with command handler
Step 4: Compile Entire Application
There is only one addition to the normal compilation process of our Win32 application. We need to add a custom build step that runs the ribbon markup compiler and we need to add the generated resource to the application.
To have your project automatically compile the ribbon markup XML file, do the following:
- First, add the RibbonMarkup.xml file to the project.
- Right click the added file in Solution Explorer and select Properties, Custom Build Step.
- Fill the fields according to the following values:
"%ProgramFiles%\Microsoft SDKs\Windows\v7.0\Bin\UICC.exe" RibbonMarkup.xml
$(IntDir)\RibbonUI.bml /header:RibbonIDs.h /res:RibbonResource.rc
Note, on 64 bit Operating Systems, the "%ProgramFiles% environment variable should be replaced with %ProgramW6432%. So the command line should be:
"%ProgramW6432%\Microsoft SDKs\Windows\v7.0\Bin\UICC.exe" RibbonMarkup.xml
$(IntDir)\RibbonUI.bml /header:RibbonIDs.h /res:RibbonResource.rc
Description: Compiling Ribbon UI markup
Now that we've done these steps, we need to compile the application at least once so that the RibbonResource.rc file gets generated.
Now we add RibbonResource.rc to the project. This will cause the compiled binary representation of the ribbon UI to be embedded as a resource in the application executable.
Finally, don't forget to add the images you used in the ribbon markup to the project folder. Make sure you use the same relative location as specified in the markup file.
Now sit back and enjoy your first ribbon enabled application.
Figure 5: First ribbon enabled application
In this post, we have seen in detail the necessary steps to create an application that uses the Windows Ribbon Framework.
A working demo of the code presented in this post can be found here.
That's it for now,