Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

AppBar - How to implement a sliding desktop bar with a simple MFC class and a DLL

0.00/5 (No votes)
10 Jul 2008 2  
An alternative to standard Windows AppBars with minimal changes to your application.

Introduction

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.

Overall Design

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.

CAppBarMngr Class

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:

//------------------------------------------------------
// Function:  Init   - Loads DLL functions and initilize mouse hook
// Arguments: _hWnd  - Handler of window to manage
//            _width - Desired width of managed window
//            _left  - True if window is left side docked, false if right sided
// Returns:   APPBARHOOK_DLLERROR - An error has occurred while loading DLL functions
//            APPBARHOOK_ALREADYHOOKED - Another instance has already hooked the mouse
//            APPBARHOOK_SUCCESS - All is OK
//---------------------------------------------------------------------

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.
  • Put #include "AppBarMngr.h" into your main file (where main window is created).
  • Create your main window, usually into yourapp::InitInstance().
  • 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:

BOOL CAppBarDemoApp::InitInstance()
{
 CMainFrame* pFrame = new CMainFrame;
 m_pMainWnd = pFrame;

 // creates a simple frame, without caption, icon or menu

 pFrame->Create(NULL, "AppBarDemo", WS_POPUP);
 
 // avoid taskbar button to appear, also removes 3D edge

 pFrame->ModifyStyleEx(WS_EX_APPWINDOW|WS_EX_CLIENTEDGE, WS_EX_TOOLWINDOW);
 // Don't show, AppBar Manager class will do

 pFrame->ShowWindow(SW_HIDE);
 pFrame->UpdateWindow();

 // Create AppBar manager thread

 CAppBarMngr *appbar = 
           (CAppBarMngr *)::AfxBeginThread(RUNTIME_CLASS(CAppBarMngr));

 // Init AppBar Manager, right sided

 int result = appbar->Init(pFrame->m_hWnd, 150, false);  // use true for left sided
 
 // Check if hooking has been successful

 if (result==APPBARHOOK_SUCCESS)
  return TRUE;
 else if (result==APPBARHOOK_DLLERROR)
  ::AfxMessageBox("Error loading AppBarHook.dll");
 // else should be APPBARHOOK_ALREADYHOOKED, close application


 return FALSE;
}

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 ::SendMessage() function.

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 CAppBarMngr.

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.

.NET Version

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.

History

  • May 3, 2005 - First edition
  • July 9, 2008 - Added multi-monitor support

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here