I searched many times on the Internet for an easy way to implement an AppBar (desktop application toolbar) but without success. Microsoft provides some WinAPI shell functions like
SHAppBarMessage (read here about it) and an old sample application (AppBar.exe). I tried it out but that was not what I expected because Shell AppBars reorganize the desktop to fit the toolbar, while I wanted a sliding bar that doesn't disturb other application windows or the desktop icons.
So, I have developed a single MFC object,
CAppBarMngr, to allow almost any application to become a sliding AppBar, with minimal changes to the application's source code. Since it is necessary to respond to mouse movements outside the application window, I had to implement a global mouse hook, which requires to generate a DLL, but you don't have to deal with the DLL internals, just to distribute with your software.
There is just one class:
CAppBarMngr, which will be responsible for sliding the application's main frame from the left or right edge of the desktop screen. As I mentioned earlier, a global hook is needed to respond appropriately to the mouse cursor position (i.e. if the side edge has been reached).
Traditionally, a global hook is implemented as a DLL that sends messages to an application's window through its
HWND handler (hook DLLs can't be MFC enabled), which requires several modifications in the application's code for receiving and managing the hook messages. In order to avoid that, however, I have tried a different approach: to send messages to a secondary thread, as explained below.
This class is derived from
CWinThread, so it is capable of receiving messages sent using WinAPI
PostThreadMessage() function, by implementing the
PreTranslateMessage() event. Also this class has some other responsibilities: to be a wrapper for the hook DLL, and to handle window movements (sliding).
CAppBarMngr has just one
public member: the
Init() function. It will be used to link the manager with the managed window. It receives three arguments as described in the source code:
int CAppBarMngr::Init(HWND _hWnd, int _width, bool _left)
How to Use It
This is all you have to do to implement AppBar into your application:
- Insert the AppBarMngr.cpp and AppBarMngr.h files into your MFC project.
#include "AppBarMngr.h" into your main file (where main window is created).
- Create your main window, usually into
- Create a thread with an MFC
::AfxBeginThread() function as shown below, saving a pointer to it.
- Call the
Init method specifying window's
HWND handler, desired width and edge.
- Verify if
Init has returned successfully.
Here is the code portion from the demo application:
CMainFrame* pFrame = new CMainFrame;
m_pMainWnd = pFrame;
pFrame->Create(NULL, "AppBarDemo", WS_POPUP);
CAppBarMngr *appbar =
int result = appbar->Init(pFrame->m_hWnd, 150, false);
else if (result==APPBARHOOK_DLLERROR)
::AfxMessageBox("Error loading AppBarHook.dll");
That's all you have to do. Also, don't forget to distribute the hook DLL (AppBarHook.dll) with your executable application; it must reside in the same directory to work properly.
Single Instance Control for Free
As it makes no sense to run two copies of the same AppBar program, the
Init() function is a notification that the hook has already been used (by returning
APPBARHOOK_ALREADYHOOKED), so, you can use it to avoid a second instance to run. Notice the last lines in the example above, if hook has been already used, then it returns
FALSE to close the application.
The Hook Project
I had to develop a project to implement the global mouse hook DLL. It has just one file: AppBarHook.cpp. I don't want to make a hook tutorial here because there are several great articles here at CodeProject. So, I will just give you some of the details.
The usual hook technique saves a windows handler (
HWND) of the receiving window for hook messages. I have used a Thread ID instead, that's why
CAppBarMngr is a thread object. So, messages are passed using WinAPI
::SendThreadMessage() instead of the
The hook will detect mouse events of possible interest to
CAppBarMngr. I say possible because the hook doesn't know about the window state and position, it knows only about the managed edge and window width. The MFC class will do the rest of the work.
The Hook DLL exports only one function:
SetHook(), which creates the global mouse hook and saves the desired width and edge. It is called by
About the Demo Application
I have created a simple demo application project for testing purpose. It has a simple
CFrameWnd derived object without frame, caption, menu or border. I have tested this with other standard MFC windows without any problem.
The demo source is a Visual C++ 6.0 project, but you will be able to open and automatically convert to a newer Visual C++ version.
If you find any bug in this application, please don't care about it. It is just for demo purposes and it is not the intention of this article. I will not describe its internals here for the same reason.
I have been requested several times for a .NET version of this control. I have started working on it. I will leave a message in the forum below when it is ready.
- May 3, 2005 - First edition
- July 9, 2008 - Added multi-monitor support