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:
Ribbon.ApplicationMenu
Ribbon.HelpButton
Ribbon.Tabs
Ribbon.ContextualTabs
Ribbon.QuickAccessToolbar
Ribbon.SizeDefinitions
While
ContextPopup
view has these:
ContextPopup.ContextMaps
ContextPopup.ContextMenus
ContextPopup.MiniToolbars
In our sample, our
Ribbon
view has 3 children:
Ribbon.ApplicationMenu
contains Exit Button and MRU List
Ribbon.Tabs
contains 4 groups of buttons
Ribbon.QuickAccessToolbar
<
Application.Views
>
<
Ribbon
>
<
Ribbon.ApplicationMenu
>
<
ApplicationMenu
CommandName
="
cmdFileMenu"
>
<
ApplicationMenu.RecentItems
>
<
RecentItems
CommandName
="
cmdMRUList"
MaxCount
="
1"
/
>
<
/ApplicationMenu.RecentItems
>
<
MenuGroup
Class
="
MajorItems"
>
<
Button
CommandName
="
cmdExit"
/
>
<
/MenuGroup
>
<
/ApplicationMenu
>
<
/
Ribbon.ApplicationMenu
>
<
Ribbon.Tabs
>
<
Tab
CommandName
="
cmdTab1"
>
<
Group
CommandName
="
cmdGroup1"
SizeDefinition
="
OneButton"
>
<
Button
CommandName
="
cmdButton1"
/
>
<
/Group
>
<
Group
CommandName
="
cmdGroup2"
SizeDefinition
="
TwoButtons"
>
<
Button
CommandName
="
cmdButton2"
/
>
<
Button
CommandName
="
cmdButton3"
/
>
<
/Group
>
<
Group
CommandName
="
cmdGroup3"
SizeDefinition
="
ThreeButtons"
>
<
Button
CommandName
="
cmdButton1"
/
>
<
Button
CommandName
="
cmdButton2"
/
>
<
Button
CommandName
="
cmdButton3"
/
>
<
/Group
>
<
Group
CommandName
="
cmdGroup4"
SizeDefinition
="
FiveOrSixButtons"
>
<
Button
CommandName
="
cmdButton3"
/
>
<
Button
CommandName
="
cmdButton4"
/
>
<
ToggleButton
CommandName
="
cmdToggleButton1"
/
>
<
Button
CommandName
="
cmdButton5"
/
>
<
ToggleButton
CommandName
="
cmdToggleButton2"
/
>
<
/Group
>
<
/
Ribbon.Tabs
>
<
Ribbon.QuickAccessToolbar
>
<
QuickAccessToolbar
CommandName
="
cmdQat"
/
>
<
/
Ribbon.QuickAccessToolbar
>
<
/Ribbon
>
<
/Application.Views
>
<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:
<
Application.Commands
>
<
Command
Name
="
cmdGroup1"
>
<
Command.SmallImages
>
<
Image
Id
="
201"
>
res/Button_Image.bmp
<
/Image
>
<
/Command.SmallImages
>
<
/Command
>
<
Command
Name
="
cmdGroup2"
/
>
<
Command
Name
="
cmdGroup3"
/
>
<
Command
Name
="
cmdGroup4"
/
>
<
Command
Name
="
cmdButton1"
>
<
Command.LabelTitle
>
<
String
Id
="
210"
>
Button 1
<
/String
>
<
/Command.LabelTitle
>
<
Command.LargeImages
>
<
Image
Id
="
211"
>
res/AddTableL.bmp
<
/Image
>
<
/Command.LargeImages
>
<
Command.SmallImages
>
<
Image
Id
="
212"
>
res/AddTableS.bmp
<
/Image
>
<
/Command.SmallImages
>
<
/Command
>
<
Command
Name
="
cmdToggleButton2"
>
<
Command.LabelTitle
>
<
String
Id
="
270"
>
ToggleButton 2
<
/String
>
<
/Command.LabelTitle
>
<
Command.SmallImages
>
<
Image
Id
="
271"
>
res/Copy.bmp
<
/Image
>
<
/Command.SmallImages
>
<
/Command
>
<
Command
Name
="
cmdQat"
/
>
<
Command
Name
="
cmdFileMenu"
/
>
<
Command
Name
="
cmdMRUList"
>
<
Command.LabelTitle
>
<
String
Id
="
280"
>
MRU List
<
/String
>
<
/Command.LabelTitle
>
<
/Command
>
<
Command
Name
="
cmdExit"
Symbol
="
IDC_CMD_EXIT"
>
<
Command.LabelTitle
>
<
String
Id
="
290"
>
Exit Button
<
/String
>
<
/Command.LabelTitle
>
<
Command.LargeImages
>
<
Image
Id
="
291"
>
res/ExitL.bmp
<
/Image
>
<
/Command.LargeImages
>
<
/Command
>
<
/Application.Commands
>
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:
uicc.exe Ribbon.xml %(Filename).bml /header:%(Filename).h /res:%(Filename).rc
And in the Outputs option, write this:
%(Filename).bml;%(Filename).h;%(Filename).rc
This will tell Visual Studio to compile our XAML file and create binary file (
Ribbon.bml
) and resource files (
Ribbon.h
and
Ribbon.rc
).
We're done with designing UI part, now we can move on to the COM part. (That's initializing the
Ribbon
control and binding the markup resource to our application.)
We need to create a basic window application that will act as the host of the
Ribbon
first.
As usual, we start with
WinMain
:
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
MSG msg;
if(CoInitialize(0))
return FALSE;
MyRegisterClass(hInstance);
if (!InitInstance (hInstance, nCmdShow))
return FALSE;
while (GetMessage(&msg, NULL, 0, 0))
TranslateMessage(&msg);
DispatchMessage(&msg);
CoUninitialize();
return (int) msg.wParam;
And then, we register window class:
ATOM MyRegisterClass(HINSTANCE hInstance)
WNDCLASSEX wcl;
wcl.cbSize = sizeof(WNDCLASSEX);
wcl.hInstance = hInstance;
wcl.lpszClassName = g_szClassName;
wcl.lpfnWndProc = WndProc;
wcl.style = 0;
wcl.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcl.hIconSm = NULL;
wcl.hCursor = LoadCursor(NULL, IDC_ARROW);
wcl.lpszMenuName = NULL;
wcl.cbClsExtra = 0;
wcl.cbWndExtra = 0;
wcl.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
if(!RegisterClassEx(&wcl)) {
return FALSE;
return TRUE;
Continue with the creation of the window:
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
HWND hWnd;
hWnd = CreateWindow(g_szClassName, g_szAppTitle,
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
return FALSE;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
And finally: the window procedure:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
switch (message)
case WM_CREATE:
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
return 0;
That's it for our basic window application. Now can finally move to the COM part. Before we continue, this article won't go into details about COM programming. I would suggest Jeff Glatt's series of article about programming COM in plain C.
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.
Must have functions for COM object:
1. QueryInterface will compare GUID,
and if it matches then fill the object
and do reference counting
2. AddRef and Release increment and
decrement the count
HRESULT STDMETHODCALLTYPE QueryInterface(IUIApplication *This, REFIID vtblID,
void **ppv)
if(!IsEqualIID(vtblID, &IID_IUIAPPLICATION)
&& !IsEqualIID(vtblID, &IID_IUnknown)) {
*ppv = 0;
return(E_NOINTERFACE);
*ppv = This;
This->lpVtbl->AddRef(This);
return(NOERROR);
ULONG STDMETHODCALLTYPE AddRef(IUIApplication *This)
return(InterlockedIncrement(&OutstandingObjects));
ULONG STDMETHODCALLTYPE Release(IUIApplication *This)
return InterlockedDecrement(&OutstandingObjects);
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.
3 must have functions for Ribbon application.
For now we're leaving this as a stub
HRESULT STDMETHODCALLTYPE OnViewChanged(IUIApplication *This, UINT32 viewId,
UI_VIEWTYPE typeID, IUnknown *view, UI_VIEWVERB verb, INT32 uReasonCode)
return E_NOTIMPL;
HRESULT STDMETHODCALLTYPE OnCreateUICommand(IUIApplication *This, UINT32 commandId,
UI_COMMANDTYPE typeID, IUICommandHandler **commandHandler)
return E_NOTIMPL;
HRESULT STDMETHODCALLTYPE OnDestroyUICommand (IUIApplication *This, UINT32 commandId,
UI_COMMANDTYPE typeID, IUICommandHandler *commandHandler)
return E_NOTIMPL;
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!
IUIApplicationVtbl is defined in UiRibbon.h and
CINTERFACE symbol stops IntelliSense from
complaining about undefined IUIApplicationVtbl identifier
IUIApplicationVtbl myRibbon_Vtbl = {QueryInterface,
AddRef,
Release,
OnViewChanged,
OnCreateUICommand,
OnDestroyUICommand};
Next, we're ready to initialize the Ribbon
. It's worth knowing how Ribbon
framework interacts with our application, take a look at this diagram:
First, we need to create an object with Ribbon
framework CLSID
:
Because we're only creating a single object of CLSID_UIRibbonFramework,
it's better to use CoCreateInstance
hr = CoCreateInstance(&CLSID_UIRibbonFramework, NULL, CLSCTX_INPROC_SERVER,
&IID_IUIFRAMEWORK, (VOID **)&g_pFramework);
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.
IUIApplication *pApplication = NULL;
pApplication = (IUIApplication *)GlobalAlloc(GMEM_FIXED, sizeof(IUIApplication));
if(!pApplication) {
return(FALSE);
Point our pApplication to myRibbon_Vtbl that contains
standard IUnknown method (QueryInterface, AddRef, Release)
and callback for our IUIApplication interface
(OnViewChanged, OnCreateUICommand, OnDestroyUICommand).
(IUIApplicationVtbl *)pApplication->lpVtbl = &myRibbon_Vtbl;
hr = pApplication->lpVtbl->QueryInterface(pApplication, &IID_IUIAPPLICATION, &ppvObj);
hr = g_pFramework->lpVtbl->Initialize(g_pFramework, hWnd, (IUIApplication *)ppvObj);
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
).
hr = g_pFramework->lpVtbl->LoadUI(g_pFramework, GetModuleHandle(NULL),
L"APPLICATION_RIBBON");
Now that our we're done with our InitializeFramework
function, all we need to do is call our newly created function in our window procedure, right in WM_CREATE
section.
case WM_CREATE:
if(!InitializeFramework(hWnd))
return(FALSE);
break;
And don't forget to do the clean up. Calling Destroy
function will release and destroy any instance of Ribbon
framework objects.
hr = ((IUIFramework *)g_pFramework)->lpVtbl->Destroy(g_pFramework);
g_pFramework = NULL;
case WM_DESTROY:
DestroyRibbon();
PostQuitMessage(0);
break;
OK, we're done!
You may test your Ribbon
application now. I hope everything goes well, and you can see Windows Ribbon
attached to your application.
What's Next?
Next, we'll be talking about Ribbon
's command handlers or how our application will respond to any property update requests or respond to execute events.
IUIApplicationVtbl not declared / unresilved symbol - MS Visual Studio C++ 2019 
Member 1362260526-Apr-21 11:00
Member 1362260526-Apr-21 11:00
IUIApplicationVtbl
.
The header file uriribbon.h is included in the project source.
how can I fix this problem ?
Re: IUIApplicationVtbl not declared / unresilved symbol - MS Visual Studio C++ 2019 
Member 143402239-May-21 6:27
Member 143402239-May-21 6:27
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.
My apologies. The reason my intellisense (and compiler itself) didn't recognise it is because they #ifdef cplusplus'd it away when actually using a C++ compiler.
Too bad it doesn't let me undo my vote of 2 and vote 5 now.
I am a C# developer and I need this Ribbon Sample but in C#.
If you could help me, I would appreciate it.
Thanks in advance
Célio
C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\Microsoft.CppCommon.targets(151,5): error MSB6006: "cmd.exe" exited with code 9009. 
Member 1146014418-Feb-15 0:10
Member 1146014418-Feb-15 0:10
C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\Microsoft.CppCommon.targets(151,5): error MSB6006: "cmd.exe" exited with code 9009.
while trying :: Windows Ribbon Framework in Win32 C Application[^]
Hi! I have read your article, but I have a problem with the implementation of the IUICommandHandler interface (I write in pure C).
My code:
DEFINE_GUID(IID_IUICommandHandler, 0xefc7bdf, 0x1fdc, 0x487a, 0xbc, 0x9b, 0x24, 0xcd, 0x19, 0x29, 0x1a, 0x17);
IUICommandHandlerVtbl CommandHandlerVtbl = {CHQueryInterface,
CHAddRef,
CHRelease,
OnExecute,
OnUpdateProperty};
IUICommandHandler *pCommandHandler = NULL;
HRESULT STDMETHODCALLTYPE OnCreateUICommand(IUIApplication *This, UINT32 commandId, UI_COMMANDTYPE typeID, IUICommandHandler **commandHandler)
{ pCommandHandler = (IUICommandHandler *)GlobalAlloc(GMEM_FIXED, sizeof(IUICommandHandler));
if (!pCommandHandler)
return E_NOTIMPL;
(IUICommandHandlerVtbl *)pCommandHandler->lpVtbl = &CommandHandlerVtbl;
return pCommandHandler->lpVtbl->QueryInterface(pCommandHandler,&IID_IUICommandHandler,(void**)commandHandler);