Getting Started with WTL

Tags

, ,

A desktop application usually has a Ribbon User Interface, the equivalent of pre-Vista era menu and toolbar, a client area and topped with an optional status bar.  WTL gives us atlribbon.h which contains the following class definitions:

CRibbonUpdateUI : allows to interact with the ribbon UI elements as we do with the status bar and toolbar items in updating and retrieving their label, check state and enabled state.

enum k_KEY : redefined most if not all the properties key available in a much user friendlier way with comments specifying to which control or type it applies to. won’t have to keep looking up each time for clues concerning a property key.

ICtrl and its implementation CtrlImpl : allows the ribbon and its controls to handle events they bind to.  WTL provides controls that map directly to the ribbon UI controls such as the Ribbon UI spinner, button, and gallery controls.  And all controls WTL provide for Ribbon UI inherit from CtrlImpl including the ribbon control itself so that may be sub classed and used to handle specific event destined for the control.  the implement controls have the following naming convention: xxxCtrlImpl where xxx stands for the control name. Example: SpinnerCtrlImpl.

CRibbonImpl implements CRibbonUpdateUI<T>, ICtrl, IUIApplication, IUICommandHandler.  It’s the heart of the implementation on the user end required by the Ribbon Framework. it handles all the little details concerning IUIApplication and IUICommandHandler for us and as usual from WTL, it provides us with member functions for common task.  If I need to throw a quick look at atlribbon.h to perform a task I would definitely start here.

Next up, its CRibbonFrameWindowImpl<> which is an empty implementation of CRibbonFrameWindowImplBase which itself inherits from CRibbonImpl.  Nothing major there to wonder about.

indeed there are many utility functions that shield us from having to work directly with CLSID.Thinking smile

Little Background on Working with the RibbonUI.

Working with the Ribbon Framework start with the Ribbon Markup declaration of the commands and controls.  the Ribbon Markup is XAML based,Party smile WPF/XAML developers, and its embedding file usually has a “.xml” extension.

Ribbon Markup follows the follow skeleton.

 

<Application xmlns=”http://schemas.microsoft.com/windows/2009/Ribbon”&gt; <Application.Commands> <Command Name=”cmdExit” LabelTitle=”Exit application” />

<!– Command declarations for the Application Menu. –>
<Command Name=”cmdFileMenu”
Symbol=”ID_FILE_MENU”
Id=”25000″ />
<!– Command declaration for most recently used items. –>
<Command Name=”cmdMRUItems”
Symbol=”ID_FILE_MRUITEMS”
Id=”25050″/>
<!– Command declarations for Application Menu items. –>
<Command Name=”cmdNew”
Symbol=”ID_FILE_NEW”
Comment=”New”
Id=”25001″
LabelTitle=”&amp;New”/>
<Command Name=”cmdOpen”
Symbol=”ID_FILE_OPEN”
Comment=”Open”
Id=”25002″
LabelTitle=”&amp;&amp;Open”/>
<Command>
<Command.Name>cmdSave</Command.Name>
<Command.Symbol>ID_FILE_SAVE</Command.Symbol>
<Command.Comment>Save</Command.Comment>
<Command.Id>25003</Command.Id>
<Command.LabelTitle>
<String>
<String.Content>Label for Save</String.Content>
<String.Id>59999</String.Id>
<String.Symbol>strSave</String.Symbol>
</String>
</Command.LabelTitle>
<Command.TooltipTitle>Tooltip title with &amp;&amp; for Save Command</Command.TooltipTitle>
<Command.TooltipDescription>Tooltip description for Save Command.</Command.TooltipDescription>
<Command.Keytip>s1</Command.Keytip>
</Command>
<Command Name=”cmdPrint”
Symbol=”ID_FILE_PRINT”
Comment=”Save”
Id=”25004″
LabelTitle=”Print” />
<Command Name=”cmdExit”
Symbol=”ID_FILE_EXIT”
Comment=”Exit”
Id=”25005″
LabelTitle=”Exit” />
<!– Command declarations for the Application Menu. –>
<Command Name=”cmdFileMenu”
Symbol=”ID_FILE_MENU”
Id=”25000″ />
<!– Command declaration for most recently used items. –>
<Command Name=”cmdMRUItems”
Symbol=”ID_FILE_MRUITEMS”
Id=”25050″/>
</Application.Commands>
<!– Control declarations for Application Menu items. –>
<Ribbon.ApplicationMenu>
<ApplicationMenu CommandName=”cmdFileMenu”>
<!– Most recently used items collection. –>
<ApplicationMenu.RecentItems>
<RecentItems CommandName=”cmdMRUItems”/>
</ApplicationMenu.RecentItems>
<!– Menu items collection. –>
<MenuGroup>
<Button CommandName=”cmdNew” />
<Button CommandName=”cmdOpen” />
<Button CommandName=”cmdSave” />
</MenuGroup>
<MenuGroup>
<Button CommandName=”cmdPrint” />
<Button CommandName=”cmdExit” />
</MenuGroup>
</ApplicationMenu>
</Ribbon.ApplicationMenu>

 

<Application.Views> <Ribbon> <Ribbon.Tabs> <Tab> <Group> <Button CommandName=”cmdExit” /> </Group> </Tab> </Ribbon.Tabs> </Ribbon> </Application.Views> </Application>

 

After the Ribbon UI XAML declaration; we compile the xml file with the UI Command Compiler (UICC) tool, the Command names and IDs are placed into a header file used by the Ribbon host application.

Compilation syntax:

UICC <ribbonFile> <binaryFile> [options]

click here for more info

extracts compilation from msdn.

After the Ribbon UI markup file has been compiled and the .rc file generated, we can start interacting with Ribboun UI controls in our application and handle event raised by the controls.

First, since the whole Ribbon UI is COM based, we have to CoCreateInstance of the IUIFramework; Initialize it by passing in two crucial parameters which are an handle to the top level window that will host our custom design UI, and a reference to an implementation of IUIApplication.

IUIApplication allows the Ribbon UI Framework to communicate back with our application.  It defines three methods.  among its three methods, implementing OnCreateUICommand allows the Ribbon UI Framework to ask our application handlers for the command we defined inside our markup.

After IUIFramework is created and initialized, we then have the framework load our UI. Once the Ribbon UI Framework has our custom design UI loaded it is shown.  By designing our Ribbon UI inside an xml file and the command handlers in Component Object Model (COM)-based interface implementations as part of our application, the Ribbon UI Framework provides us an easy and clean separation of presentation and logic read more.

WTL ribbon infrastructures relies on atlapp.h to check for the current version of Windows on which the app is running,  load propsys.dll, and then create an instance of IUIFramework for us.  So, we do not have to CoCreateInstance of the IUIFramework.

CRibbonImp implements IUIApplication for us.  so we do not have to even concern ourselves with IUIApplication implementation details.  it also implements IUICommandHandler and inherits CRibbonUpdateUI.   CRibbonUpdateUI enables us to update  ribbon controls’ states and property with ease in a online function call.  CRibbonImpl has instance methods that cover a broad range of scenarios such as accessing the Framework underlying IUIFramework, or even the IUIRibbon which provides the ability to specify settings and properties for a ribbon.  It has methods to Create the Ribbon UI and access it its different components such as the Quick Access control, the View,  handling the Contextual menu tab request, specifying docking position for the QA control, etc..   To make it short, just inherit from CRibbonFrameImpl<> and set m_hWndClient member variable to our defined main frameless window(our View) and we’re good to go.

CRibbonUpdateUI gives us the usual WTL environment paradigm, where we can set and get UI controls Text, Enabled state, Checked state,

With the quick overview behind me, lets see what WTL wizard has to offer when it comes to the Ribbon.

image

image

 

image

Its always good to check “Use a  view window”. it should allow us to construct our personal view-document where the view present the models and the documents handles retrieving/persisting and housing the model; kind of like a super-charged controller and Model at once. Sorry, no binding available in c++ for Windows versions prior to Win8.

The wizard does a great job.  It delivers everything necessary to get running and more.  So  what happen when I compile and run the boiler plate WTL wizard gives us?

Error    1    error MSB6006: “cmd.exe” exited with code -1073741511.    C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V120\Microsoft.CppCommon.targets    170    5    Rib2

Sad smile

Bing-ing around the web, and trying to connect the dots, I think it has something to do with Visual Studio or more precisely its compiler not finding the the Ribbon framework UICC tool.  but I am wrong.  checking the properties of each and every file and playing around with their settings reveals that ribbon.xml item type property needs to be changed from Custom Build Tool to something else that does not required being compiled such as xml.

image

 

Next, I receive a

Error    1    error C1083: Cannot open include file: ‘atlframe.h': No such file or directory    c:\s\wtltrainnings\rib2\rib2.cpp    6    1    Rib2

this sort of error calls for directory inclusion for the required header files.

image

nice, but now I want to play a bit with our nice ribbon xml definition file.

Before editing our Ribbon.xml definition file, I added the UICC.xsd to the list of schemas used by visual studio express in order to have intellicense.   Make sure to open Ribbon.xml file using visual studio builtin xml editor.

hmmm, lets start out with a change in the Ribbon background. To do this, call the member function SetRibbonColor, passing UI_PKEY_GlobalBackgroundColor  and  UI_HSB(2, 0, 254) as parameters.  I chose to perform the task inside the MainFrm.h on create handler, right after the ribbon is shown.  Now, lets fetch some icons from web, what about zoom in and out, plus edit? found a few, but they came as pngs. Ribbon UI supports pngs on windows 8 and later and not on my Win 7; thus, I have to convert the pngs to bmps.

Next, lets remove or at best disable the app menu and move the exit command to the quick access tool bar and add another tab for view options.

<!– Tabs –>
<Command Name=”TabHome” Symbol=”ID_TAB_HOME”
LabelTitle=”Home” />

<Command Name=”TabView” Symbol=”ID_TAB_VIEW”
LabelTitle=”View” />
<Command Name=”TabBnjr” Symbol=”ID_TAB_BONJOUR”
LabelTitle=”Bounjour” />

<!–  Home tab Groups –>
<Command Name=”GroupClipboard” Symbol=”ID_GROUP_CLIPBOARD”
LabelTitle=”Clipboard” />
<!–<Command Name=”GroupView” Symbol=”ID_GROUP_VIEW”
LabelTitle=”View” />–>

<!–  View tab Groups –>
<Command Name=”GroupZoom” Symbol=”ID_GROUP_ZOOM”
LabelTitle=”Zoom” />
<Command Name=”GroupView” Symbol=”ID_GROUP_VIEW”
LabelTitle=”View” />

 

<Command Name=”wtl_ZOOM_IN” Symbol=”ID_ZOOM_IN” Id=”0xE810″ LabelTitle=”Zoom In” TooltipTitle=”Zoom In!” LabelDescription=”Click to zoom in further!” TooltipDescription=”TooltipDesctiption zoom fdasf” >
<Command.LargeImages>
<Image Source=”images\zoomin.bmp”  MinDPI=”96″ />
</Command.LargeImages>
<Command.SmallImages>
<Image Source=”images\zoomin.bmp”  MinDPI=”96″ />
</Command.SmallImages>
</Command>
<Command Name=”wtl_ZOOM_OUT” Symbol=”ID_ZOOM_OUT” Id=”0xE812″ LabelTitle=”Zoom out”>
<Command.LargeImages>
<Image Source=”images\zoomout.bmp”  MinDPI=”96″ />
</Command.LargeImages>
<Command.SmallImages>
<Image Source=”images\zoomout.bmp”  MinDPI=”96″ />
</Command.SmallImages>
</Command>
<Command Name=”wtl_FULL_SCREEN” Symbol=”ID_FULL_SCREEN” Id=”0xE814″ LabelTitle=”Full Screen”>
<Command.LargeImages>
<Image Source=”images\fullScreen.bmp”  MinDPI=”96″ />
</Command.LargeImages>
<Command.SmallImages>
<Image Source=”images\fullScreen.bmp”  MinDPI=”96″ />
</Command.SmallImages>
</Command>

Accomplished everything I set to do except hiding or disabling the app menu.  that is either a limitation by the underlying framework or WTL or a bug in WTL.  I tried all three of the following inside the onCreate handler right after the ribbon is shown but to no avail:

//UIEnable(ID_RIBBON_APP_MENU, FALSE);
SetProperty(ID_RIBBON_APP_MENUSND, UI_PKEY_Enabled, FALSE);
InvalidateProperty(ID_RIBBON_APP_MENUSND, UI_PKEY_Enabled, UI_INVALIDATIONS_ALLPROPERTIES);

I even called the UIEnable function again inside the overriden OnIdle function.

Next up, lets handle two commands since the usual user story includes some sort of response as a result of user interacting with the toolbar.  Simply merge our COOMAND_HANDLER  inside the BEGIN_MSG_MAP and END_MSG_MAP() two COMMAND_ID_HANDLERs.

BEGIN_MSG_MAP(CMainFrame)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
COMMAND_ID_HANDLER(ID_APP_EXIT, OnFileExit)
COMMAND_ID_HANDLER(ID_FILE_NEW, OnFileNew)
COMMAND_ID_HANDLER(ID_VIEW_STATUS_BAR, OnViewStatusBar)
COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)
COMMAND_ID_HANDLER(ID_ZOOM_OUT, OnZoomOut)
COMMAND_ID_HANDLER(ID_ZOOM_IN, OnZoomIn)
        CHAIN_MSG_MAP(CRibbonFrameWindowImpl<CMainFrame>)
END_MSG_MAP()

and define the handlers as follow:

LRESULT OnZoomOut(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
MessageBox(L”BLAzz ZOOM out clicked”, L”Bnjr”, MB_OK);
return 0;
}

image

Ideally, I wouldn’t handle the commands or even map such commands directly from the frame window (the Shell); rather I would forward such command to the View and let the view handle interaction with the user and let some command travel even further down the stack to the document.  In this scenario, I have not implemented a document.

In the next post, I’ll go over DWM. which WTL also puts at out finger tip by also referencing it inside atlribbon.h  for ribbon apps.

Follow

Get every new post delivered to your Inbox.