You are currently offline, waiting for your internet to reconnect

How To Add Toolbars and Tooltips to ActiveX Controls

This article was previously published under Q194294
Retired KB Content Disclaimer
This article was written about products for which Microsoft no longer offers support. Therefore, this article is offered "as is" and will no longer be updated.
An ActiveX control can have a toolbar (a CToolBar class) as its childwindow. This article shows a way to create such a toolbar and also how toimplement tooltips for buttons on the toolbar window.
Visual C++ provides two methods to create a toolbar. The article desribeshow to create a toolbar resource using the Resource Editor. If you alreadyhave a bitmap resource, please refer to the online documentation"Converting Bitmaps to Toolbars" for converting your bitmap resource to atoolbar resource.

Steps are shown below:

  1. Use the MFC ActiveX Control Wizard to generate an MFC ActiveX control.
  2. Create a Toolbar resource in the control's project.
  3. Add a tooltip string resource for each button in the toolbar. These tooltip string resources will be loaded in the TTN_NEEDTEXT notification code handler.
  4. Add a WH_GETMESSAGE hook callback function to the ActiveX control- derived class. The hook procedure is in charge of calling the application's PreTranslateMessage(), and this results in the call to FilterToolTipMessage(), which activates tooltips. A hook procedure is needed because the ActiveX control is just like an inproc server[ASCII 151]no message pump is found:
          HHOOK hHook = NULL;      // Hook procedure for WH_GETMESSAGE hook type.      LRESULT CALLBACK GetMessageProc(int nCode, WPARAM wParam, LPARAM         lParam)      {        // Switch the module state for the correct handle to be used.        AFX_MANAGE_STATE(AfxGetStaticModuleState( ));        // If this is a keystrokes message, translate it in controls'        // PreTranslateMessage().        LPMSG lpMsg = (LPMSG) lParam;        if( (nCode >= 0) &&          PM_REMOVE == wParam &&          AfxGetApp()->PreTranslateMessage(lpMsg))        {           lpMsg->message = WM_NULL;           lpMsg->lParam = 0L;           lpMsg->wParam = 0;        }       // Passes the hook information to the next hook procedure in       // the current hook chain.       return ::CallNextHookEx(hHook, nCode, wParam, lParam);      }					
  5. Create the toolbar window (a CToolBar class), which is a child window of the ActiveX control. This is done in response to WM_CREATE message. In addition, WM_CREATE message handler is also a good place to install the WH_GETMESSAGE hook procedure.
          int CCToolBarCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)      {         if (COleControl::OnCreate(lpCreateStruct) == -1)            return -1;         // Create a CToolBar window which is a child of ActiveX control.         if (!m_ToolBar.Create(this,               WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_TOOLTIPS) ||              !m_ToolBar.LoadToolBar(IDR_TOOLBAR))            {               TRACE0("Failed to create toolbar\n");               return -1;      // fail to create            }         // Toolbar has to have TBSTYLE_TOOLTIPS style. Otherwise,         // notification handler for TTN_NEXTTEXT won't be called.         m_ToolBar.ModifyStyle (0, TBSTYLE_TOOLTIPS);         // Move the toolbar so it is VISIBLE on the screen.         CRect rc;         GetClientRect(&rc);         rc.bottom = + 34;         m_ToolBar.MoveWindow(&rc);         // Because ActiveX control is an inproc server, it does not have a         // message pump. So, messages to child windows created by the         // ActiveX control are not going to be received by the control.         // Thus, we set up a message hook to call PreTranslateMessage().         // This results in the call to FilterToolTipMessage(), which         // activates tooltips.         hHook = ::SetWindowsHookEx(            WH_GETMESSAGE,            GetMessageProc,            AfxGetInstanceHandle(),            GetCurrentThreadId());         ASSERT (hHook);         return 0;      }					
  6. Uninstall the message hook function in response to WM_DESTROY message:
          void CCToolBarCtrl::OnDestroy()      {         // Remove the message hook function.         VERIFY (::UnhookWindowsHookEx (hHook));         COleControl::OnDestroy();      }					
  7. Add a TTN_NEEDTEXTW (for Unicode notification code) or TTN_NEEDTEXTA (for ANSI notification code) notification handler to the ActiveX control-derived class. Load the tooltip string to be displayed in this notification code handler:
          BEGIN_MESSAGE_MAP(CCToolBarCtrl, COleControl)         //<AngularNoBind>{{</AngularNoBind>AFX_MSG_MAP(CCToolBarCtrl)         ON_WM_CREATE()         ON_COMMAND(ID_BUTTON1, OnButton1) // first button on toolbar         ON_COMMAND(ID_BUTTON2, OnButton2) // second button on toolbar         ON_COMMAND(ID_BUTTON3, OnButton3) // third button on toolbar         ON_WM_DESTROY()         //<AngularNoBind>}}</AngularNoBind>AFX_MSG_MAP         ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)         // ANSI notification code (for Windows 95)         ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipNotify)         // Unicode notification code (for NT)         ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipNotify)      END_MESSAGE_MAP()      // Notification handler for tooltips - determine which tooltip      // string resource to be displayed.      BOOL CCToolBarCtrl::OnToolTipNotify(         UINT id, NMHDR * pNMHDR, LRESULT * pResult)      {         TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*) pNMHDR;         TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*) pNMHDR;         int strid = 0;         switch (pNMHDR->idFrom)         {         case ID_BUTTON1:            strid = IDS_BUTTON1;            break;         case ID_BUTTON2:            strid = IDS_BUTTON2;            break;         case ID_BUTTON3:            strid = IDS_BUTTON3;            break;         }  if (strid)       {          *pResult = 0;            CString str;          str.LoadString(strid);            #define _countof(array) (sizeof(array)/sizeof(array[0]))            #ifndef _UNICODE          if (pNMHDR->code == TTN_NEEDTEXTA)          lstrcpyn(pTTTA->szText, str, _countof(pTTTA->szText));          else          _mbstowcsz(pTTTW->szText, str, _countof(pTTTW->szText));          #else          if (pNMHDR->code == TTN_NEEDTEXTA)          _wcstombsz(pTTTA->szText, str, _countof(pTTTA->szText));          else          lstrcpyn(pTTTW->szText, str, _countof(pTTTW->szText));          #endif             return TRUE;        }         return FALSE;      } 					
(c) Microsoft Corporation 1998, All Rights Reserved. Contributions by Yeong-Kah Tam, Microsoft Corporation.
ocx kbDSupport