www.pudn.com > 属性页源代码_disable_tab.zip > TabCtrlEx.cpp


///////////////////////////////////////////////////////////////////////////// 
// TabCtrlEx.cpp : implementation file 
// 
// Extended Tab Control 
// Copyright (C) 1998 RedCreek Communications 
// All rights reserved. 
// 
// Written by Kevin Lussier (klussier@redcreek.com) 
// Version 1.02 
// 
// Distribute freely, except: don't remove my name from the source or 
// documentation (don't take credit for my work), mark your changes (don't 
// get me blamed for your possible bugs), don't alter or remove this 
// notice. 
// No warrantee of any kind, express or implied, is included with this 
// software; use at your own risk, responsibility for damages (if any) to 
// anyone resulting from the use of this software rests entirely with the 
// user. 
// 
// Send bug reports, bug fixes, enhancements, requests, flames, etc. to 
//    klussier@redcreek.com 
///////////////////////////////////////////////////////////////////////////// 
 
#include "stdafx.h" 
#include "TabCtrlEx.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
// Define our offsets for drawing 
#define TCEX_SELECTED_XOFFSET	7 
#define TCEX_SELECTED_YOFFSET	0 
#define TCEX_UNSELECTED_XOFFSET	4 
#define TCEX_UNSELECTED_YOFFSET	2 
#define CXBUTTONMARGIN			2 
#define CYBUTTONMARGIN			3 
 
///////////////////////////////////////////////////////////////////////////// 
// CTabCtrlEx 
 
CTabCtrlEx::CTabCtrlEx() 
{ 
} 
 
CTabCtrlEx::~CTabCtrlEx() 
{ 
} 
 
 
BEGIN_MESSAGE_MAP(CTabCtrlEx, CTabCtrl) 
	//{{AFX_MSG_MAP(CTabCtrlEx) 
	ON_NOTIFY_REFLECT(TCN_SELCHANGING, OnSelchanging) 
	ON_WM_DESTROY() 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// CTabCtrlEx message handlers 
///////////////////////////////////////////////////////////////////////////// 
/* 
 * DrawItem 
 * 
 * Purpose: 
 *   This is the function that draws the tab items (bitmaps and text) for 
 *   this owner-drawn control 
 * 
 * Inputs: 
 *   LPDRAWITEMSTRUCT lpd: Contains vital drawing information 
 * 
 * Returns: 
 *   Nothing 
 * 
 * Note: 
 *   This function is the heart of the extended tab control. It draws the 
 *   items enabled or disabled, with or without images. There are bound to 
 *   be flaws here, especially in the drawing code but for simple tabs it 
 *   seems to work fairly well. 
 */ 
void CTabCtrlEx::DrawItem(LPDRAWITEMSTRUCT lpd) 
{ 
	// Make sure it's a tab control 
	if ( lpd->CtlType != ODT_TAB ) { 
		TRACE0( "CTabCtrlEx::DrawItem() - Ignoring non-tab control\r\n" ); 
		return; 
	} 
 
	// Get whether or not this item is enabled 
	BOOL bIsEnabled = IsItemEnabled( lpd->itemID ); 
 
	// Get this item's text 
	TC_ITEM tci; 
	memset( &tci, 0, sizeof( TC_ITEM ) ); 
	tci.mask = TCIF_TEXT | TCIF_IMAGE; 
	char buf[255]; 
	tci.pszText = buf; 
	tci.cchTextMax = 255; 
	if ( !GetItem( lpd->itemID, &tci ) ) { 
		TRACE1( "Failed to get item %d\r\n", lpd->itemID ); 
		return; 
	} 
 
	// Create a CRect 
	CRect rect( lpd->rcItem ); 
	// Draw the background 
	FillRect( lpd->hDC, rect, (HBRUSH)(CTLCOLOR_DLG + 1) ); 
	// Adjust the rectangle 
	if ( lpd->itemState & ODS_SELECTED ) { 
		// Push it right 
		rect.left += TCEX_SELECTED_XOFFSET; 
		// Push it down 
		rect.top += TCEX_SELECTED_YOFFSET; 
	} 
	else { 
		// Push it right 
		rect.left += TCEX_UNSELECTED_XOFFSET; 
		// Push it down 
		rect.top += TCEX_UNSELECTED_YOFFSET; 
	} 
 
	// Set the background mode (paint transparent) 
	SetBkMode( lpd->hDC, TRANSPARENT ); 
 
	// If this item has an image, draw it 
	if ( tci.iImage >= 0 ) { 
		// Get the image list 
		CImageList *il = GetImageList(); 
		ASSERT( il != NULL ); 
		// Figure out where exactly we want to put the bitmap 
		CPoint pt( rect.TopLeft() ); 
		// Adjust the rectangle 
		if ( lpd->itemState & ODS_SELECTED ) { 
			// Push it down 
			pt.y += CYBUTTONMARGIN; 
		} 
		// Draw it 
		CDC hDC; 
		hDC.Attach( lpd->hDC ); 
		if ( bIsEnabled ) { 
			il->Draw( &hDC, tci.iImage, pt, ILD_NORMAL ); 
		} 
		else { 
			// use DrawState to draw disabled button: must convert to icon 
			HICON hIcon = il->ExtractIcon( tci.iImage ); 
			ASSERT(hIcon); 
			hDC.DrawState( pt, CSize(0,0), hIcon, DSS_DISABLED, (HBRUSH)NULL ); 
			DestroyIcon(hIcon); 
		} 
		hDC.Detach(); 
		// Push the text over 
		IMAGEINFO ii; 
		il->GetImageInfo( tci.iImage, &ii ); 
		rect.left += (ii.rcImage.right - ii.rcImage.left); // Add the width of the bitmap 
		rect.left += CXBUTTONMARGIN; // Plus some separation 
	} 
 
	// We will need to remember the current color 
	COLORREF origCol; 
	// Draw disabled 
	if ( bIsEnabled ) { 
		// Set the text color for our hilight (remember the original color) 
		origCol = SetTextColor( lpd->hDC, GetSysColor( COLOR_BTNTEXT ) ); 
		// Draw the text 
		DrawText( lpd->hDC, buf, -1, rect, DT_SINGLELINE | DT_LEFT | DT_VCENTER ); 
	} 
	// Draw enabled 
	else { 
		// Set the text color for our hilight (remember the original color) 
		origCol = SetTextColor( lpd->hDC, GetSysColor( COLOR_3DHILIGHT ) ); 
		// Draw the text 
		DrawText( lpd->hDC, buf, -1, rect + CPoint(1,1), DT_SINGLELINE | DT_LEFT | DT_VCENTER ); 
		// Set the text color for our gray text 
		SetTextColor( lpd->hDC, GetSysColor( COLOR_GRAYTEXT ) ); 
		// Draw the text 
		DrawText( lpd->hDC, buf, -1, rect, DT_SINGLELINE | DT_LEFT | DT_VCENTER ); 
	} 
 
	// Restore the original text color 
	SetTextColor( lpd->hDC, origCol ); 
} 
 
LRESULT CTabCtrlEx::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)  
{ 
	// TODO: Add your specialized code here and/or call the base class 
	if ( message == TCM_SETCURSEL ) { 
		if ( !IsItemEnabled( wParam ) ) { 
			// We only calculate a different selection if the 
			// user used CTRL+Tab or CTRL+Shift+Tab. We determine 
			// this by checking if the difference between the 
			// current and the new selection is 1 (or -1) 
			int curSel = GetCurSel(), nCount = GetItemCount(); 
			int diff = wParam - curSel, adiff = abs( diff ); 
			if ( adiff == 1 || adiff == (int)wParam || adiff == curSel ) { 
				// OK, let's find the next one 
				BOOL bNext = ( diff == 1 ) || ( diff < -1 ); 
 
				// Find the next enabled item 
				int sel = FindNextEnabled( wParam, bNext ); 
				if ( sel >= 0 ) { 
					// Set the current selection to the next enabled 
					CTabCtrl::SetCurSel( sel ); 
					return (LRESULT)0; 
				} 
			} 
			// Return indicating not to select wParam 
			return (LRESULT)-1; 
		} 
	} 
 
	// We could have checked for these keys in a TCN_KEYDOWN handler, 
	// but it's just as easy to do it here... 
 
	// Check for and process arrow keys 
	if ( message == WM_KEYDOWN ) { 
		if ( wParam == VK_RIGHT || wParam == VK_DOWN ) { 
			// Get the current selection 
			int curSel = GetCurSel(); 
			// Set the current tab 
			SetCurrentTab( curSel < GetItemCount() - 1 ? curSel + 1 : 0 ); 
			// Return indicating that we processed the message 
			return (LRESULT)0; 
		} 
		if ( wParam == VK_LEFT || wParam == VK_UP ) { 
			// Get the current selection 
			int curSel = GetCurSel(); 
			// Set the current tab 
			SetCurrentTab( curSel > 0 ? curSel - 1 : GetItemCount() - 1 ); 
			// Return indicating that we processed the message 
			return (LRESULT)0; 
		} 
	} 
 
	return CTabCtrl::WindowProc(message, wParam, lParam); 
} 
 
 
///////////////////////////////////////////////////////////////////////////// 
// Message Map Functions 
///////////////////////////////////////////////////////////////////////////// 
void CTabCtrlEx::OnSelchanging(NMHDR* pNMHDR, LRESULT* pResult)  
{ 
	// TODO: Add your control notification handler code here 
	// Get the position of the last message 
	DWORD lastPos = GetMessagePos(); 
	// Convert it to a point 
	CPoint point( LOWORD( lastPos ), HIWORD( lastPos ) ); 
	// Convert the point to client coordinates 
	ScreenToClient( &point ); 
	// Create a hit test 
	TC_HITTESTINFO hti; 
	hti.pt = point; 
	hti.flags = TCHT_ONITEM; 
	// See which (if any) tab was hit 
	int nItem = HitTest( &hti ); 
	if ( nItem == -1 ) { 
		// Fail the selection change 
		*pResult = 1; 
		return; 
	} 
	// Set the result based on whether or not the item is enabled 
	BOOL bResult = IsItemEnabled( nItem ); 
 
	// If the page is active, then send the kill message to check 
	// whether or not the page wants to change 
	if ( bResult ) { 
		// Send the kill active page message 
		bResult = SendKillActive(); 
	} 
 
	// Return our result (TRUE to stop, FALSE to proceed) 
	*pResult = !bResult; 
} 
 
 
///////////////////////////////////////////////////////////////////////////// 
// Protected Functions 
///////////////////////////////////////////////////////////////////////////// 
 
/* 
 * FindNextEnabled 
 * 
 * Purpose: 
 *   Finds the next enabled tab on the control. 
 * 
 * Inputs: 
 *   int nStart: The index of then item to start the search 
 *   BOOL bNext: TRUE to search next, FALSE to search previous 
 * 
 * Returns: 
 *   Index of next enabled item found, -1 if no item was found 
 */ 
int CTabCtrlEx::FindNextEnabled( int nStart, BOOL bNext ) 
{ 
	// Get the number of item we have 
	int i, nCount = GetItemCount(); 
	// Check if we should go next or back 
	if ( bNext ) { 
		// Search all the next items 
		for ( i = nStart; i < nCount; i++ ) { 
			if ( IsItemEnabled( i ) ) { 
				// Found one, return it 
				return i; 
			} 
		} 
		// We didn't find it, loop and start from the beginning 
		for ( i = 0; i < nStart; i++ ) { 
			if ( IsItemEnabled( i ) ) { 
				// Found one, return it 
				return i; 
			} 
		} 
	} 
	else { 
		// Search all the previous items 
		for ( i = nStart; i >= 0; --i ) { 
			if ( IsItemEnabled( i ) ) { 
				// Found one, return it 
				return i; 
			} 
		} 
		// We didn't find it, loop and start from the end 
		for ( i = (nCount - 1); i > nStart; --i ) { 
			if ( IsItemEnabled( i ) ) { 
				// Found one, return it 
				return i; 
			} 
		} 
	} 
	// Didn't find one 
	return -1; 
} 
 
/* 
 * SetCurrentTab 
 * 
 * Purpose: 
 *   Sets the current tab selection and sends the TCM_SELCHANGE 
 *   notification so that the dialog is properly updated 
 * 
 * Inputs: 
 *   int nItem: The item that is to be the current tab 
 * 
 * Returns: 
 *   Nothing 
 */ 
void CTabCtrlEx::SetCurrentTab( int nItem )  
{ 
	// Make sure the item is in our range 
	if ( nItem < 0 || nItem >= GetItemCount() ) { 
		return; 
	} 
 
	// Send the kill active page message 
	if ( !SendKillActive() ) { 
		// The kill message returned that the page should not 
		// be changed, so we don't do it 
		return; 
	} 
 
	// Set the current selection 
	SetCurSel( nItem ); 
 
	// SetCurSel does not send the TCN_SELCHANGE notification 
	m_nmhdr.hwndFrom = GetSafeHwnd();  
	m_nmhdr.idFrom = GetDlgCtrlID(); 
	m_nmhdr.code = TCN_SELCHANGE;   
	// Send the message 
	SendMessage( WM_NOTIFY, m_nmhdr.idFrom, (LPARAM)&m_nmhdr ); 
} 
 
/* 
 * SendKillActive 
 * 
 * Purpose: 
 *   Sends a kill active message to a property page of a parent 
 *   property sheet 
 * 
 * Inputs: 
 *   int nItem: The index of the page to send the kill message to 
 * 
 * Returns: 
 *   TRUE if the kill message succeeds, FALSE otherwise 
 */ 
BOOL CTabCtrlEx::SendKillActive( int nItem ) 
{ 
	// Send a message to our parent to kill the current active window 
	CWnd *pParent = GetParent(); 
	if ( pParent->IsKindOf( RUNTIME_CLASS( CPropertySheet ) ) ) { 
		// Check if the user wants to use the active page 
		if ( nItem == -1 ) { 
			nItem = ((CPropertySheet *)pParent)->GetActiveIndex(); 
		} 
		// Get the property page 
		CPropertyPage *page = ((CPropertySheet *)pParent)->GetPage( nItem ); 
#ifdef _DEBUG 
		CString txt; 
		page->GetWindowText( txt ); 
		TRACE2( "Sending kill active message to property page #%d (%s)\r\n", nItem, (LPCSTR)txt ); 
#endif // _DEBUG 
		m_nmhdr.hwndFrom = pParent->GetSafeHwnd(); 
		m_nmhdr.idFrom = pParent->GetDlgCtrlID(); 
		m_nmhdr.code = PSN_KILLACTIVE; 
		// PSN_KILLACTIVE will return TRUE to prevent the page from losing activation 
		// and FALSE to to allow it 
		return !page->SendMessage( WM_NOTIFY, m_nmhdr.idFrom, (LPARAM)&m_nmhdr ); 
	} 
	// Return success - Send kill active to non-propertysheet does nothing 
	return TRUE; 
} 
 
 
///////////////////////////////////////////////////////////////////////////// 
// Public Functions 
///////////////////////////////////////////////////////////////////////////// 
/* 
 * Install 
 * 
 * Purpose: 
 *   Installs the extended tab control 
 * 
 * Inputs: 
 *   CTabCtrl *pTabCtrl: The tab control that we will subclass 
 * 
 * Returns: 
 *   TRUE if install succeeds, FALSE otherwise 
 * 
 * Note: 
 *   Install() MUST be called, even if the extended tab control is not 
 *   subclassing a property sheet tab control. In that case, create 
 *   the tab control using its Create() function, and then call install 
 *   with a pointer to the control itself. Install() recognizes when 
 *   this occurs and does not attempt to subclass itself. The style 
 *   bit and image list are still set as normal. In the case where the 
 *   tab control is used in a dialog as part of DDX and Create() is not 
 *   called directly, Install() must still be called with a pointer to 
 *   the extended tab control. Neither of these two cases has actually 
 *   been tested by me at this point, but it sounds right. If you try 
 *   this and it doesn't work, let me know... 
 */ 
BOOL CTabCtrlEx::Install( CTabCtrl *pTabCtrl ) 
{ 
	ASSERT( pTabCtrl ); 
 
	TRACE0( "Installing extended tab control\r\n" ); 
	// Subclass the window, but only if it's not us 
	if ( pTabCtrl != this ) { 
		// Subclass the tab control 
		if ( !SubclassWindow( pTabCtrl->GetSafeHwnd() ) ) { 
			TRACE0( "Failed to subclass tab control\r\n" ); 
			// Return failure 
			return FALSE; 
		} 
	} 
	// Get our current style 
	DWORD dStyle = pTabCtrl->GetStyle(); 
	// Add the owner-drawn bit 
	dStyle |= TCS_OWNERDRAWFIXED; 
	// Set the style 
	SetWindowLong( GetSafeHwnd(), GWL_STYLE, dStyle ); 
 
	// Return success 
	return TRUE; 
} 
 
/* 
 * Install 
 * 
 * Purpose: 
 *   Installs the extended tab control 
 * 
 * Inputs: 
 *   CPropertySheet *pPropSheet: The property sheet that contains 
 *     the tab control that we will subclass 
 * 
 * Returns: 
 *   TRUE if install succeeds, FALSE otherwise 
 */ 
BOOL CTabCtrlEx::Install( CPropertySheet *pPropSheet ) 
{ 
	ASSERT( pPropSheet ); 
 
	// Call the install function for the tab control 
	return( Install( pPropSheet->GetTabControl() ) ); 
} 
 
/* 
 * EnableItem 
 * 
 * Purpose: 
 *   Enabled or disables an item in the tab control 
 * 
 * Inputs: 
 *   int nItem: The item to enable or disable 
 *   BOOL bEnable: TRUE to enable the item, FALSE to disable it 
 * 
 * Returns: 
 *   TRUE if function succeeds, FALSE otherwise 
 */ 
BOOL CTabCtrlEx::EnableItem( int nItem, BOOL bEnable ) 
{ 
	// Make sure the item is in our range 
	if ( nItem < 0 || nItem >= GetItemCount() ) { 
		// Return failure 
		return FALSE; 
	} 
 
	// See if this item is already in our disabled list 
	int idx = -1; 
	BOOL bIsEnabled = IsItemEnabled( nItem, &idx ); 
 
	// Does the caller want to enable or disable this item? 
	// If our state is the same as what the user wants to do, 
	// then we're done 
	if ( bEnable == bIsEnabled ) { 
		// Return success 
		return TRUE; 
	} 
 
	// We come here if we have to add or remove from our list 
	if ( bEnable ) { 
		// Mark this item as enabled 
		ASSERT( idx >= 0 ); 
		m_disabled.RemoveAt( idx ); 
	} 
	else { 
		// Check if this item is the current item. If it is, 
		// then we select a new current item (if we can) 
		int curSel = GetCurSel(); 
		if ( nItem == curSel ) { 
			// Find the next enabled item 
			int sel = FindNextEnabled( nItem < GetItemCount() - 1 ? nItem + 1 : 0, TRUE ); 
			// If there isn't one or the next one is the 
			// one we're trying to disable, then we can't 
			// disable this item 
			if ( sel < 0 || sel == nItem) { 
				// We didn't find an enabled item, return failure 
				return FALSE; 
			} 
			// Set the current selection 
//			SetCurSel( sel ); 
			SetCurrentTab( sel ); 
		} 
		// Mark this item as disabled 
		m_disabled.Add( nItem ); 
	} 
 
	// Invalidate the item 
	RECT rect; 
	GetItemRect( nItem, &rect ); 
	InvalidateRect( &rect ); 
	 
	// Return success 
	return TRUE; 
} 
 
/* 
 * IsItemEnabled 
 * 
 * Purpose: 
 *   Specifies whether an item is enabled or disabled 
 * 
 * Inputs: 
 *   int nItem: The item whose enable state we will get 
 * 
 * Outputs: 
 *   int *disabledIdx: The index of the item in the disabled list 
 * 
 * Returns: 
 *   TRUE if the item is enabled, FALSE if it is not 
 */ 
BOOL CTabCtrlEx::IsItemEnabled( int nItem, int *disabledIdx ) 
{ 
	// Make sure the item is in our range 
	if ( nItem < 0 || nItem >= GetItemCount() ) { 
		// Return failure 
		return FALSE; 
	} 
 
	// Find the item in our list 
	int dCount = m_disabled.GetSize(); 
	for ( int idx = 0; idx < dCount; idx++ ) { 
		if ( m_disabled[idx] == (DWORD)nItem ) { 
			// Found it, return failure (indicates disabled) 
			if ( disabledIdx != NULL ) { 
				// Set the disabled index 
				*disabledIdx = idx; 
			} 
			// Return failure 
			return FALSE; 
		} 
	} 
	// Didn't find it, return success (indicates enabled) 
	return TRUE; 
} 
 
/* 
 * SetItemImage 
 * 
 * Purpose: 
 *   Adds an image into the tab control's image list and specifies 
 *   the item that will use this image 
 * 
 * Inputs: 
 *   int nItem: The item that will be associated with the image 
 *   int nResBmp: The resource ID of the image bitmap 
 *   int nResMsk: The resource ID of the image mask (also a bitmap resource) 
 * 
 * Returns: 
 *   The index into the image list if successful, -1 otherwise 
 */ 
int CTabCtrlEx::SetItemImage( int nItem, int nResBmp, int nResMsk ) 
{ 
	// Make sure the item is in our range 
	if ( nItem < 0 || nItem >= GetItemCount() ) { 
		// Return failure 
		return -1; 
	} 
 
	// Get the image list 
	CImageList *il = GetImageList(); 
	if ( il == NULL ) { 
		TRACE0( "No image list defined\r\n" ); 
		return -1; 
	} 
	// If the user only specified the bitmap and not the mask, 
	// we use the bitmap as the mask 
	if ( nResMsk == -1 ) { 
		TRACE0( "CTabCtrlEx::SetItemImage - No mask specified so using bitmap as mask\r\n" ); 
		nResMsk = nResBmp; 
	} 
 
	// Load the bitmap resource 
	CBitmap bitmap; 
	if ( !bitmap.LoadBitmap( nResBmp ) ) { 
		TRACE0( "Failed to load bitmap\r\n" ); 
		// Return failure 
		return -1; 
	} 
	// Load the mask resource 
	CBitmap mask; 
	if ( !mask.LoadBitmap( nResMsk ) ) { 
		TRACE0( "Failed to load mask\r\n" ); 
		// Delete the bitmap object 
		bitmap.DeleteObject(); 
		// Return failure 
		return -1; 
	} 
 
	// Add this bitmap to our list 
	int result = il->Add( &bitmap, &mask ); 
	 
	// Delete the bitmap object 
	bitmap.DeleteObject(); 
	// Delete the mask object 
	mask.DeleteObject(); 
 
	// Check to see if the image was added 
	if ( result == -1 ) { 
		TRACE1( "Failed to add bitmap and mask to image list for item %d\r\n", nItem ); 
		// Return failure 
		return -1; 
	} 
	// Set the item's image index 
	TC_ITEM tci; 
	memset( &tci, 0, sizeof( TC_ITEM ) ); 
	tci.mask = TCIF_IMAGE; 
	tci.iImage = result; 
	if ( !SetItem( nItem, &tci ) ) { 
		TRACE1( "Failed to set image for item %d\r\n", nItem ); 
		// Return failure 
		return -1; 
	} 
	// Return the image index 
	return result; 
} 
 
/* 
 * SetItemImage 
 * 
 * Purpose: 
 *   Adds an image into the tab control's image list and specifies 
 *   the item that will use this image 
 * 
 * Inputs: 
 *   int nItem: The item that will be associated with the image 
 *   HICON hIcon: An HICON to use as the image 
 * 
 * Returns: 
 *   The index into the image list if successful, -1 otherwise 
 */ 
int CTabCtrlEx::SetItemImage( int nItem, HICON hIcon ) 
{ 
	// Make sure the item is in our range 
	if ( nItem < 0 || nItem >= GetItemCount() ) { 
		// Return failure 
		return -1; 
	} 
 
	// Get the image list 
	CImageList *il = GetImageList(); 
	if ( il == NULL ) { 
		TRACE0( "No image list defined\r\n" ); 
		return -1; 
	} 
 
	// Add this bitmap to our list 
	int result = il->Add( hIcon ); 
	// Check to see if the image was added 
	if ( result == -1 ) { 
		TRACE1( "Failed to add icon to image list for item %d\r\n", nItem ); 
		// Return failure 
		return -1; 
	} 
	// Set the item's image index 
	TC_ITEM tci; 
	memset( &tci, 0, sizeof( TC_ITEM ) ); 
	tci.mask = TCIF_IMAGE; 
	tci.iImage = result; 
	if ( !SetItem( nItem, &tci ) ) { 
		TRACE1( "Failed to set image for item %d\r\n", nItem ); 
		// Return failure 
		return -1; 
	} 
	// Return the image index 
	return result; 
} 
 
void CTabCtrlEx::OnDestroy()  
{ 
	CTabCtrl::OnDestroy(); 
}