CodeGuru
Earthweb Search
Forums Wireless Jars Gamelan Developer.com
CodeGuru Navigation
RSS Feeds

RSSAll

RSSVC++/C++

RSS.NET/C#

RSSVB

See more EarthWeb Network feeds

follow us on Twitter

Member Sign In
User ID:
Password:
Remember Me:
Forgot Password?
Not a member?
Click here for more information and to register.

Become a Marketplace Partner

jobs.internet.com

internet.commerce
Partners & Affiliates
















Home >> Visual C++ / C++ >> COM-based Technologies >> ATL & WTL Programming >> ATL


Superclassed Ownerdrawn Standard Windows Control Using ATL
Rating: none

Naveen Kohli (view profile)
April 27, 1999

This article is an initial attempt to create an ActiveX control based on window's control. In this article I have spuerclassed ListBox control to create an ownerdraw control. This ListBox contains text strings and user can specify the zero based index value to put divider lines in the list. For creation of the skeleton code for the control please refer to the Microsoft's sample SUBEDIT, POLYGON tutuorial and my other article in this section "ActiveX Control Tutorial". I will just explain the steps which are different or need some explanation for superclassing.

Superclassing is a technique that allows an application to create a new window class with the basic functionality of the existing class, plus enhancements provided by the application. A superclass is based on an existing window class called the base class. Frequently, the base class is a system global window class such as an edit control, static control, etc. but it can be any window class. To create this control, follow all the steps for inserting a full control into the control project using ATL Object Wizard. The only difference will be on the Miscellaneous page of the Object Wizard for Add control based on option.
(continued)



ATL Class Wizard

Since we are creating a ListBox, so from all the available options (Edit, Button, Static, ListBox, ComboBox, Scroll Bar, etc.) pick ListBox. And make sure that Windowed Only checkbox is also checked.

After the code has been inserted, the constructor code should look something like this


CListBoxControlX::CListBoxControlX () :
		m_ctlListBox (_T("ListBox"), this, 1)
{
	m_bWindowOnly = TRUE;
}

The constructor sets the m_bWindowOnly to TRUE. This data member is inherited from CComControlBase and is used to instruct ATL never to allow windowless activation. Otherwise the control will not be able to handle WM_CREATE message for the control window and control will not get created in response to that message. The WM_CREATE message is used to create the one time creation of the ATL control. The Object Wizard adds code in the WM_CREATE handler for the control to create the specified (in this case ListBox) common control. It also adds code to handle the correct sizing of the contained control based on the size of the ATL control. The code for control creation looks like this,


LRESULT
CListBoxControlX::OnCreate (UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
DWORD dwStyle = (WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL |
WS_BORDER |	LBS_DISABLENOSCROLL | LBS_OWNERDRAWFIXED | LBS_NOTIFY |
LBS_HASSTRINGS);

	RECT rc;
	GetWindowRect(&rc);
	rc.right -= rc.left;
	rc.bottom -= rc.top;
	rc.top = rc.left = 0;
	m_ctlListBox.Create(m_hWnd, rc, NULL, dwStyle);
	return 0;
}

The thing to note in the function is window styles used. Since it's a ownerdraw ListBox containing strings only, there we put LBS_OWNERDRAWFIXED, LBS_HASSTRINGS styles. And this ListBox is to notify its parent about the messages it generates it has to have LBS_NOTIFY style also.

Being an ownerdraw control, its painting will not be handled by OnPaint. The parent window sends WM_DRAWITEM message to the control window to draw itself. There we need to handle this message in the message map of our ActiveX control. The map looks like this:


BEGIN_MSG_MAP(CListBoxControlX)
	MESSAGE_HANDLER(WM_CREATE, OnCreate)
	MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
	MESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem)
	MESSAGE_HANDLER(WM_COMMAND, OnSelectionChange)
	CHAIN_MSG_MAP(CComControl)
	DEFAULT_REFLECTION_HANDLER ()
ALT_MSG_MAP(1)
	// Replace this with message map entries for superclassed ListBox
END_MSG_MAP()

You can see we have handled WM_COMMAND message in the map. This has been added to handle the clicks inside the ListBox control to inform the parent window that selected item has changed. The way this works is, parent window gets LBN_SELCHANGE message when the ListBox selection change. The parent window reflects it to the control window. Since the parent of ListBox gets all the messages through WM_COMMAND, there we can handle the LBN_KILLFOCUS, LBN_DBLCLK, etc messages. This is necessary to handle these events in more COM-centric way. After the message is reflected to control window, then we make sure that user has not selected divider line. If so, we will not fire any event for this selection and let the default message handler take care of it. The message handling code is:


LRESULT
CListBoxControlX::OnSelectionChange (UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&
bHandled)
{
	long curSel;
	DWORD wNotifyCode, wID;
	HWND hwndCtl = NULL;

	// Get the notification message and the handle to control window.

	wNotifyCode = HIWORD (wParam);
	wID = LOWORD (wParam);
	hwndCtl = HWND (lParam);

	if (wNotifyCode == LBN_SELCHANGE && !FAILED (GetCurSel (&curSel)) &&
		hwndCtl == m_ctlListBox.m_hWnd) {
		if (FindDividerIndex (curSel) == -1) {
			Fire_SelectionChange ();
			return 0;
		}
	}

	m_ctlListBox.DefWindowProc(uMsg, wParam, lParam);
	return 0;
}

Similarly to handle all other messages, we can perform appropriate checks and add events for connection points. Therefore when you are inserting control with the help of Object Wizard, the option for adding connection point support is checked.

I have added some other interfaces in the control's inheritance, like IObjectSafetyImpl, IQuickActivateImpl, IPersistPropertyBagImpl and IPersistStreamInitImpl. The significance of these interfaces has been discused in my ActiveX Control Tutorial article. These don't get added by wizard, instead you will have to add then in the header file manually.

For specifying color of divider line, I have added a property of type OLE_COLOR to the interface and to manipulate this at design time, an entry for this has been added in the property map so that it appears in the color property page of the interface.


BEGIN_PROP_MAP(CListBoxControlX)
	PROP_DATA_ENTRY("_cx", m_sizeExtent.cx, VT_UI4)
	PROP_DATA_ENTRY("_cy", m_sizeExtent.cy, VT_UI4)
	PROP_ENTRY("Font", DISPID_FONT, CLSID_StockFontPage)
	PROP_ENTRY("DividerLine Color", DISPID_DIVIDERLINECOLOR,
CLSID_StockColorPage)
END_PROP_MAP()

I have tried to put all the useful methods for ListBox manipulation which have one to one correspondence with MFC's ClistBox class for handling ListBox.


STDMETHOD(GetCount)(/*[out]*/ long *plNumItems);
STDMETHOD(FindString)(/*[in]*/ long lIndexAfter, /*[in]*/ BSTR bstrItem, /*[out]*/ long *plRetIndex);
STDMETHOD(ResetContent)();
STDMETHOD(DeleteString)(/*[in]*/ long lIndex, /*[out]*/ long *plNumItems);
STDMETHOD(InsertString)(/*[in]*/ long lIndex, /*[in]*/ BSTR bstrItem, /*[out]*/ long *plRetPos);
STDMETHOD(RemoveDividerIndex)(/*[in]*/ long lIndex, /*[out]*/ long *plRetPos);
STDMETHOD(AddDividerIndex)(/*[in]*/ long lIndex);
STDMETHOD(SetCurSel)(/*[in]*/ long lIndex);
STDMETHOD(GetCurSel)(/*[out]*/ long *plIndex);
STDMETHOD(AddString)(/*[in]*/ BSTR bstrItem);

The difference being that following the COM rules, each of these methods return HRESULT value. And to implement each one of the methods, Win32 API calls have been used because we are not taking any MFC support for it. For example SetCurSel method for setting current selected object has been implemented like this:


STDMETHODIMP
CListBoxControlX::SetCurSel (long lIndex)
{
	// Do some initial checks.

	if (!::IsWindow(m_hWnd)) {
		return Error (OLESTR ("Invalid or NULL window handler for the ListBox control"),
			IID_IListBoxControlX, E_FAIL);
	}

	if (::SendMessage (m_ctlListBox.m_hWnd, LB_SETCURSEL, (int)lIndex, 0L) == LB_ERR) {
		return Error (OLESTR ("Failed to set the current selection to requested index"),
				IID_IListBoxControlX, E_FAIL);
	}

	return S_OK;
}

It sends LB_SETCURSEL message to ListBox control's window.

To store the divider line indices, I have made use of vector data type from STL. At top of ListBoxControlX.h file, I have defined typedef for this data type storing long type values.


typedef vector<long> LONGVECTOR;

To use STL some minor modifications need to be made in the project. In the stdafx.h file, you need to put the following block of code. Otherwise vector type will not be recoganized by compiler.


#include <vector>
#if _MSC_VER > 1020
 using namespace std;
#endif

And in the project settings, goto to C++ tab. In the category type, choose C++ Language and then on this page make sure that Enabling exception handling checkbox is checked. I have tried to put very descriptive remarks at the start of each function in the source code. Since I can't explain each and every thing in this article, therefore I would appreciate if you could take some time to read those descriptions.

The attached code includes a project, which demonstrates how to use this ListBox control in a dialog box. I have tried to take care of most the bugs and problems with the use of this control. This is kind of Version 1 for this control. I will add more functionality to this control in future. But if you come across some serious problem with the control, feel free to bring it to my notice. I will really appreciate that.

ATL Class Wizard

The attached code has been compiled using VC++6 (SP2) on WinNT (SP 4). Control Project - ATLListBoxControl Client Project - ListBoxClientApp

Download source - 44 KB

Tools:
Add www.codeguru.com to your favorites
Add www.codeguru.com to your browser search box
IE 7 | Firefox 2.0 | Firefox 1.5.x
Receive news via our XML/RSS feed







RATE THIS ARTICLE:   Excellent  Very Good  Average  Below Average  Poor  

(You must be signed in to rank an article. Not a member? Click here to register)

Latest Comments:
ATL project - Legacy CodeGuru (02/10/2004)
A very little improvment - Legacy CodeGuru (06/19/2002)
Superclassed Ownerdrawn Standard Windows Control Using ATL - - Legacy CodeGuru (10/19/2000)
fails to instantiate - Legacy CodeGuru (01/06/2000)
Problem with selection change event? - Legacy CodeGuru (07/29/1999)

View All Comments
Add a Comment:
Title:
Comment:
Pre-Formatted: Check this if you want the text to display with the formatting as typed (good for source code)



(You must be signed in to comment on an article. Not a member? Click here to register)

internet.comearthweb.comDevx.commediabistro.comGraphics.com

Search:

Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

Jupitermedia Corporate Info

Legal Notices, Licensing, Reprints, Permissions, Privacy Policy.
Advertise | Newsletters | Tech Jobs | Shopping | E-mail Offers

Whitepapers and eBooks

Intel Whitepaper: Comparing Two- and Four-Socket Platforms for Server Virtualization
IBM Solutions Brief: Go Green With IBM System xTM And Intel
HP eBook: Simplifying SQL Server Management
IBM Contest: Are You the Next Superstar? Join the "Search for the XML Superstar" Contest to Find Out
Microsoft PDF: Top 10 Reasons to Move to Server Virtualization with Hyper-V
Microsoft PDF: Six Reasons Why Microsoft's Hyper-V Will Overtake Vmware
Microsoft Step-by-Step Guide: Hyper-V and Failover Clustering
Intel PDF: Quad-Core Impacts More Than the Data Center
Intel PDF: Virtualization Delivers Data Center Efficiency
Go Parallel Article: PDC 2008 in Review
Microsoft PDF: Top 11 Reasons to Upgrade to Windows Server 2008
Avaya Article: Communication-Enabled Mashups: Empowering Both Business Owners and IT
Intel Whitepaper: Building a Real-World Model to Assess Virtualization Platforms
  PDF: Intel Centrino Duo Processor Technology with Intel Core2 Duo Processor
Microsoft Article: Build and Run Virtual Machines with Hyper-V Server 2008
Go Parallel Article: Q&A with a TBB Junkie
IBM Whitepaper: Innovative Collaboration to Advance Your Business
Internet.com eBook: Real Life Rails
IBM eBook: The Pros and Cons of Outsourcing
Internet.com eBook: Best Practices for Developing a Web Site
IBM CXO Whitepaper: The 2008 Global CEO Study "The Enterprise of the Future"
Avaya Article: Call Control XML in Action - A CCXML Auto Attendant
IBM CXO Whitepaper: Unlocking the DNA of the Adaptable Workforce--The Global Human Capital Study 2008
Adobe Acrobat Connect Pro: Web Conferencing and eLearning Whitepapers
HP eBook: Guide to Storage Networking
MORE WHITEPAPERS, EBOOKS, AND ARTICLES