Introduction

There's a project started at Microsoft called Hilo with the aim of helping native programmers to build high performance, responsive rich client applications. This article will try to explore Hilo's chapter 10 (Using the Windows Ribbon) in pure C.

Background

Ribbon is a nice control & highly visual. And as stated on MSDN, Ribbon has all these characteristics:

Single UI for all command

Visible & self explanatory

Labelled grouping

Modal but not hierarchical

Direct & immediate

Spacious

Has application button & quick access toolbar (QAT)

Minimal customization

Improved keyboard accessibility

What I really like from Ribbon is that it's adaptive. When we resize window, Ribbon control will be automatically resized, we don't need to write special function to handle window layout changes.

The adaptiveness of Ribbon is because of the separation of presentation and visual attributes (UI) and command logic. (We'll talk about this later.)

Another great feature in Ribbon that is worth mentioning is galleries. Galleries is basically a list box control with graphics inside it, enabling user to do live previewing.

In order to use Ribbon, we need Windows SDK 7.0 (SDK 7.0 contains uuic.exe needed for compiling XAML file and creating binary (BML file) and resource file). And for the client using our application, they need to run Windows 7 or Windows Vista with SP2 & platform updates.

Creating Ribbon and Adding It To Our Application

The creation of Ribbon is divided into 2 major tasks:

Designing UI (markup code)

Making connection to our command handler / callback through COM

OK, let's start with the design of UI. Ribbon's markup code is created as an XAML file, where the markup consists of 2 elements: <Application.Views> and <Application.Commands>.

<Application.Views> There're 2 type of views: Ribbon view and ContextPopup view. To see the difference between these 2 views, let's us see the pictures below:

<Application.Commands> We'll skip this part, as this article will not explain about connecting to our Ribbon command handler yet. Right now, it's adequate to know that Symbol attribute (e.g.: IDC_CMD_EXIT) will be used to connect to our command handler:

Remember about compiling XAML file and creating BML file we talked before? Now, it's the time for us to do this. But before we compile the XAML file we created earlier, please make sure uuic.exe can be found by Visual Studio.

You can add Windows SDK's bin folder to Visual Studio Executable Directories like the picture below:

Are we ready now? Oh, wait a minute. We need to tell Visual Studio how to compile our Ribbon markup and what to output.

You can do right clicking on the XAML file we created before (that we're going to compile), and change Item Type in the General option to Custom Build Tool, after that we can change Command Line option (in the new General option under Custom Build Tool) to something like this:

We know that every COM object must have 3 functions: QueryInterface, AddRef, and Release. We'll start creating these 3 functions. First QueryInterface, this function compares our GUID with our already defined IID_IUIAPPLICATION. If it matches, point our IUIApplication interface to our Ribbon obj, and do reference counting. And if it doesn't match, simply return E_NOINTERFACE.

For AddRef and Release, we'll only increment or decrement the reference count.

Because every application that's going to use Ribbon framework will be implementing IUIApplication interface (this is where callback entry-point methods defined), there're another 3 must have functions: OnViewChanged, OnCreateUICommand, OnDestroyUICommand.

OnViewChanged is called when there's a change in view (Ribbon or ContextPopup view)

OnCreateUICommand is called to bind Command (we specified before in our markup code) with IUICommandHandler (interface that defines method for gathering Command information and handling Command events)

And the last one, OnDestroyUICommand is (as we can see from the name of the function) called when the application is destroyed.

We're now simply returning E_NOTIMPL for these 3 functions, because we're not yet implementing it.

Remember that we're accessing Ribbon framework through COM? That's why now our VTable must have and must be started with QueryInterface, AddRef, Release and followed by our IUIApplication's functions. Please watch for the order!

And then we call our COM's QueryInterface function where in turn we get IUIApplication object pointer. This object pointer will be passed in Ribbon framework's Initialize function as we try to connect our host application with Ribbon framework.

If everything goes well, we can continue to bind the markup resource with our application, and now our application knows when to makes command-related callbacks at run time. LoadUI function will handle this.

Take a look at LoadUI's params. The second param is our application instance (in which we're simply passing NULL to GetModuleHandle function to get a handle to the file used to create the calling process, that's our own application). And the third param is our compiled binary markup (default will be APPLICATION_RIBBON).

Comments and Discussions

There is no such thing as a IUIApplicationVtbl in my Uiribbon.h header file.
I understand the logic but there is no such thing and so it won't compile.
I guess if I want to try it the C rather than C++ way I'll have to create this struct of function pointers myself.

I created with Visual C++ 2010 a MFC application with ribbon. I have added buttons to this ribbon, but I do not know how to add images to these buttons. I tried editing writelarge.bmp file from the project, and setting the index of image on these buttons, but now the ribbon icons looks very ugly. Is there an easy way to add icons to ribbon images, other than editing writelarge.bmp file from the project?

I want to disable Quick Access Toolbar and to configure image (16x16) for Groups of the Tabs.
How can I do that?
How can I change the RibbonMarkup.xml?

I don't know how to set the Dialog box button too.

Can I add buttons / tabs / groups into Quick Access Toolbar but limit that funcionality for certain buttons? For example, a contextual Tab that is hidden at a certain time and it was added to QAT. How to remove it when I hide the contextual Tab?