Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version
Go to top

Reading and Writing Messages in Outlook Express

, 27 Mar 2006
This article was done to provide an example of IStoreNamespace / IStoreFolder.
/*|*\
|*|  File:      JRTSLinkCtrl.cpp
|*|  
|*|  By:        James R. Twine, JRTwine Software, LLC.
|*|             Copyright 2002, JRTwine Software, LLC.
|*|  Date:      Tuesday, May 2, 2002
|*|             
|*|  Notes:     This Is The Implementation Of A "Correctly Behaving" Link
|*|             Control a'la Internet Explorer.  It Correctly Acts Like
|*|             A Button And Can Be Focused And Activated Via Keyboard.
|*|             It Can Also Be Dragged Onto An Instance Of Internet
|*|             Explorer To Have The Link Opened In That Instance.
|*|             
|*|             May Be Freely Incorporated Into Projects Of Any Type
|*|             **EXCEPT** For "Ad-Ware", "Spy-Ware", Or "Mass-Emailing"
|*|				(Spamming) Applications, Subject To The Following Conditions:
|*|             
|*|             o This Header Must Remain In This File, And Any
|*|               Files Derived From It
|*|             o Do Not Misrepresent The Origin Of This Code
|*|               (IOW, Do Not Claim You Wrote It)
|*|             
|*|             A "Mention In The Credits", Or Similar Acknowledgement,
|*|             Is *NOT* Required.  It Would Be Nice, Though! :)
|*|             
|*|             Tab-Size For This File Is "4".  If The Following 2 Boxes
|*|             Do Not Line Up Correctly, Your Tab Settings Are Not Correct
|*|				For This File, Or Someone Else Messed The File Up! :)
|*|             +---+---+
|*| 			|	|   |
|*|             +---+---+
\*|*/
#include	"stdafx.h"
#include	"JRTSLinkCtrl.h"
#include	<AFXOLE.h>

#include <winuser.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

HCURSOR			CJRTSLinkCtrl::ms_hCursor = NULL;
const	UINT	CF_SHELLURL = ::RegisterClipboardFormat( CFSTR_SHELLURL );

/////////////////////////////////////////////////////////////////////////////
// CJRTSLinkCtrl

/**/	CJRTSLinkCtrl::CJRTSLinkCtrl()
{
	//
	//	Initialize Dfaults...
	//
	m_crBackground = ::GetSysColor( COLOR_BTNFACE );
	m_crDisabled = ::GetSysColor( COLOR_GRAYTEXT );
	m_crActive = ::GetSysColor( COLOR_HIGHLIGHT ); //RGB( 0x00, 0x00, 0xFF );
	m_crHotTrack = ::GetSysColor( COLOR_HOTLIGHT ); //RGB( 0x00, 0x00, 0xFF );
	m_crVisited = RGB( 0x80, 0x00, 0x80 ); //::GetSysColor( COLOR_BTNTEXT );
	m_dwLastError = ERROR_SUCCESS;
	m_dwStyle = ( LCS_HOTTRACK | LCS_DRAGDROP | 
			LCS_TOOLTIPS );
	return;													// Done!
}


/**/	CJRTSLinkCtrl::~CJRTSLinkCtrl()
{
	return;													// Done!
}



BEGIN_MESSAGE_MAP(CJRTSLinkCtrl, CWnd)
	//{{AFX_MSG_MAP(CJRTSLinkCtrl)
	ON_WM_PAINT()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_KEYDOWN()
	ON_WM_MOUSEMOVE()
	ON_WM_KILLFOCUS()
	ON_WM_SETCURSOR()
	ON_WM_ERASEBKGND()
	ON_WM_ENABLE()
	ON_WM_SETFOCUS()
	ON_WM_LBUTTONDBLCLK()
	ON_WM_MBUTTONDBLCLK()
	ON_WM_MBUTTONDOWN()
	ON_WM_MBUTTONUP()
	ON_WM_RBUTTONDBLCLK()
	ON_WM_RBUTTONDOWN()
	ON_WM_RBUTTONUP()
	//}}AFX_MSG_MAP
	ON_MESSAGE( WM_MOUSELEAVE, OnMouseLeave )
	ON_MESSAGE( WM_MOUSEHOVER, OnMouseHover )
END_MESSAGE_MAP()


DWORD	CJRTSLinkCtrl::ModifyLCStyle( DWORD dwRemove, DWORD dwAdd )
{
	DWORD	dwOldStyle = m_dwStyle;							// Store Old Style For Later

	if( dwRemove )											// If Removing Some Styles
	{
		m_dwStyle &= ~( dwRemove & LCS_PUBLICMASK );		// Remove Specified Style(s)
	}
	if( dwAdd )												// If Adding Some Styles
	{
		m_dwStyle |= ( dwAdd & LCS_PUBLICMASK );			// Add Specified Style(s)
	}
	RedrawWindow();											// Redraw

	return( dwOldStyle );									// Done!
}


void	CJRTSLinkCtrl::SetTarget( LPCTSTR cpTarget )
{
	m_sTarget = cpTarget ? cpTarget : _T( "" );				// Set Target As Specified
	m_dwStyle |= LCS_I_USEURL;								// Add In Use URL Flag
	if( IsWindow( m_hWnd ) )								// If We Are Created
	{
		RedrawWindow();										// Trigger Redraw
	}
	return;													// Done!
}


void	CJRTSLinkCtrl::SetTarget( const SHELLEXECUTEINFO &seiSEI )
{
	m_seiSEI = seiSEI;										// Copy Structure
	m_dwStyle &= ~LCS_I_USEURL;								// Remove Use URL Flag
	if( IsWindow( m_hWnd ) )								// If We Are Created
	{
		RedrawWindow();										// Trigger Redraw
	}
	return;													// Done!
}


void	CJRTSLinkCtrl::SetDisplay( LPCTSTR cpDisplay )
{
	m_sDisplay = cpDisplay ? cpDisplay : _T( "" );			// Set Target As Specified
	if( IsWindow( m_hWnd ) )								// If We Are Created
	{
		RedrawWindow();										// Trigger Redraw
	}
	return;													// Done!
}


void	CJRTSLinkCtrl::SetNormalFont( const LOGFONT &lfNormal )
{
	if( (HFONT)m_fFont )									// If Already Created
	{
		m_fFont.DeleteObject();								// Free It
	}
	m_fFont.CreateFontIndirect( &lfNormal );				// Create "Normal" Font

	return;													// Done!
}


void	CJRTSLinkCtrl::SetULFont( const LOGFONT &lfUL )
{
	if( (HFONT)m_fULFont )									// If Already Created
	{
		m_fULFont.DeleteObject();							// Free It
	}
	m_fULFont.CreateFontIndirect( &lfUL );					// Create "UL" Font

	return;													// Done!
}


void	CJRTSLinkCtrl::Initialize( void )
{
	RECT	rClient;

	//
	//	If You Get An Error About "OCR_HAND", You Did Not Read
	//	The Documentation... 
	//
	ms_hCursor = (HCURSOR)::LoadImage( 0, 
			MAKEINTRESOURCE( 32649 ), IMAGE_CURSOR, 
			0, 0, ( LR_DEFAULTSIZE | LR_SHARED ) );			// Try To Load System Hand Cursor

	GetClientRect( &rClient );								// Get Client Rect
	m_ttToolTips.Create( this );							// Create The TT Control
	m_ttToolTips.AddTool( this, m_sToolTip.GetLength() ? 
		m_sToolTip : m_sTarget.GetLength() ? m_sTarget : 
		m_sDisplay, &rClient, 1 );							// Add Default Tool
	m_ttToolTips.Activate( TRUE );							// Activate TT

	return;													// Done!
}


void	CJRTSLinkCtrl::SetToolTip( LPCTSTR cpToolTip )
{
	m_sToolTip = cpToolTip ? cpToolTip : _T( "" );			// Store Tooltip Text
	if( IsWindow( m_hWnd ) )								// If We Are Created
	{
		m_ttToolTips.UpdateTipText( m_sToolTip, this, 1 );	// Update ToolTip's Tip Text
	}
	return;													// Done!
}


DWORD	CJRTSLinkCtrl::BuildFlags( void )
{
	DWORD	dwFlags = 0;

	//
	//	Build Flags...  (Maybe Using ::GetKeyboardState Would Be Faster...?)
	//
	dwFlags |= ( ::GetAsyncKeyState( VK_LCONTROL ) & 0x8000 ) ? LCF_LCTRL : 0;
	dwFlags |= ( ::GetAsyncKeyState( VK_RCONTROL ) & 0x8000 ) ? LCF_RCTRL : 0;
	dwFlags |= ( ::GetAsyncKeyState( VK_LSHIFT ) & 0x8000 ) ? LCF_LSHIFT : 0;
	dwFlags |= ( ::GetAsyncKeyState( VK_RSHIFT ) & 0x8000 ) ? LCF_RSHIFT : 0;
	dwFlags |= ( ::GetAsyncKeyState( VK_LMENU ) & 0x8000 ) ? LCF_LALT : 0;
	dwFlags |= ( ::GetAsyncKeyState( VK_RMENU ) & 0x8000 ) ? LCF_RALT : 0;
	dwFlags |= ( ::GetAsyncKeyState( VK_CONTROL ) & 0x8000 ) ? LCF_CTRL : 0;
	dwFlags |= ( ::GetAsyncKeyState( VK_SHIFT ) & 0x8000 ) ? LCF_SHIFT : 0;
	dwFlags |= ( ::GetAsyncKeyState( VK_MENU ) & 0x8000 ) ? LCF_ALT : 0;

	return( dwFlags );										// Return Flags
}


DWORD	CJRTSLinkCtrl::SendNotify( UINT uiCode, DWORD dwRetVal )
{
	NMLINKCTRL	nmlcNMLC;
	const MSG	*pMsg = GetCurrentMessage();
	CWnd		*pParent = GetParent();
	
	::memset( &nmlcNMLC, 0, sizeof( NMLINKCTRL ) );			// Init Structore
	if( pParent )											// If Parent Window Available
	{
		UINT	uiCtrlID = GetDlgCtrlID();		

		_ASSERTE( pMsg );									// (In)Sanity Check
		nmlcNMLC.m_hdr.code = uiCode;						// Set Code As Required
		nmlcNMLC.m_hdr.hwndFrom = m_hWnd;					// Set Originating HWND
		nmlcNMLC.m_hdr.idFrom = uiCtrlID;					// Set Originating ID
		nmlcNMLC.m_dwRetVal = dwRetVal;						// Set Default Return Value As Required
		nmlcNMLC.m_dwFlags = BuildFlags();					// Set Flags
		nmlcNMLC.m_ptWhere = pMsg -> pt;					// Set Cursor Location

		pParent -> SendMessage( WM_NOTIFY, (WPARAM)uiCtrlID,
				(LPARAM)&nmlcNMLC );						// Send Notification Message
	}
	return( nmlcNMLC.m_dwRetVal );							// Return RetVal
}



void	CJRTSLinkCtrl::Activate( void )
{
	if( !SendNotify( NMLC_ACTIVATE, TRUE ) )				// Send Notification Message
	{														// If Return Back With FALSE
		return;												// Do Not Activate
	}
	m_dwStyle |= LCS_VISITED;								// Set Visited Style (Success Or Failure, We Activated The Link)

	if( m_dwStyle & LCS_I_USEURL )							// If Using The URL
	{														// (We Build The SEI Structire)
		::memset( &m_seiSEI, 0, sizeof( 
				SHELLEXECUTEINFO ) );						// Init The Structure
		m_seiSEI.cbSize = sizeof( SHELLEXECUTEINFO );		// Set Size
		m_seiSEI.hwnd = m_hWnd;								// Set HWND
		m_seiSEI.lpVerb = _T( "open" );						// Set Verb
		m_seiSEI.lpFile = m_sTarget.GetLength() ? 
				m_sTarget : m_sDisplay;						// Set Target To Open
		m_seiSEI.nShow = SW_SHOWNORMAL;						// Show Normal
	}
	//
	//	If LCS_I_USEURL Not Set, The Developer Has Setup
	//	The SEI Structure Him/HerSelf...
	//
	if( ( !::ShellExecuteEx( &m_seiSEI ) ) || 				// Try To Activate The Link
			( int( m_seiSEI.hInstApp ) <= 32 ) )				
	{														// If Failed
		m_dwLastError = ::GetLastError();					// Store Last Error Code
	}
	else													// If Successful
	{
		m_dwLastError = ERROR_SUCCESS;						// Set Success Code
	}
	return;													// Done!
}


/////////////////////////////////////////////////////////////////////////////
// CJRTSLinkCtrl message handlers

LRESULT	CJRTSLinkCtrl::OnMouseLeave( WPARAM, LPARAM )
{
	TRACKMOUSEEVENT	tmeTME;

	tmeTME.cbSize = sizeof( TRACKMOUSEEVENT );				// Init Size
	tmeTME.dwFlags = TME_CANCEL;							// Init Flags
	tmeTME.hwndTrack = m_hWnd;								// Init Tracking Window
	tmeTME.dwHoverTime = 0;									// Init Hover Time

	_TrackMouseEvent( &tmeTME );							// Cancel Tracking
	m_dwStyle &= ~LCS_I_TRACKING;							// Unset Tracking Flag
	SendNotify( NMLC_MOUSELEAVE, 0 );						// Send Notification Message
	RedrawWindow();											// Redraw Entire Control

	return( 0 );											// Done!
}


LRESULT	CJRTSLinkCtrl::OnMouseHover( WPARAM, LPARAM )
{
	SendNotify( NMLC_MOUSEHOVER, 0 );						// Send Notification Message

	return( 0 );											// Done!
}


void	CJRTSLinkCtrl::OnPaint() 
{
	CPaintDC	dcDC( this ); // device context for painting
	CRect		rClient;
	bool		bIsOn = false;
	int			iDCState = dcDC.SaveDC();					// Save DC State;
	int			iSpaceX = ( ::GetSystemMetrics( SM_CXEDGE ) );
	int			iSpaceY = ( ::GetSystemMetrics( SM_CYEDGE ) );

	if( !(HFONT)m_fFont )									// If "Normal" Font Not Yet Created
	{
		LOGFONT	lfFont;

		GetFont() -> GetLogFont( &lfFont );					// Get Normal Font
		m_fFont.CreateFontIndirect( &lfFont );				// Create "Normal" Font
	}
	if( !(HFONT)m_fULFont )									// If "UL" Font Not Yet Created
	{
		LOGFONT	lfFont;

		GetFont() -> GetLogFont( &lfFont );					// Get Normal Font
		lfFont.lfUnderline = TRUE;							// Set UL Flag
		m_fULFont.CreateFontIndirect( &lfFont );			// Create "UL" Font
	}
	GetClientRect( rClient );								// Get Client Area
	if( GetStyle() & WS_DISABLED )							// If Control Is Disabled
	{
		dcDC.SetTextColor( m_crDisabled );					// Set Text To Disabled Color
	}
	else													// If Not Disabled		
	{
		if( m_dwStyle & LCS_VISITED )						// If Visited
		{
			dcDC.SetTextColor( m_crVisited );				// Set "Visited" Color
		}
		else												// If Not Yet "Visited"
		{
			dcDC.SetTextColor( m_crActive );				// Set "Normal" Color
		}
	}
	if( ( m_dwStyle & LCS_HOTTRACK ) && ( m_dwStyle & 		// If HotTracking, And Currently 
			LCS_I_TRACKING ) )								// Tracking The Mouse
	{														
		POINT	ptWhere = GetCurrentMessage() -> pt;		// Store Mouse Location At Time Of Message
		
		ScreenToClient( &ptWhere );							// Convert Location
		if( rClient.PtInRect( ptWhere ) )					// If In Our DRAWING Area
		{
			dcDC.SelectObject( m_fULFont );					// Select In "UL" Font
			dcDC.SetTextColor( m_crHotTrack );				// Set HotTrack Color
			bIsOn = true;									// Set "On" State
		}
		else												// If Not
		{
			dcDC.SelectObject( m_fFont );					// Select In "Normal" Font
		}
	}
	else													// If Not
	{
		dcDC.SelectObject( m_fULFont );						// Select In UL Font
	}
	SIZE	szExtent = dcDC.GetTextExtent( m_sDisplay );	// Get Text Extent (Drawn Size Area)

	m_rLinkArea.left = iSpaceX;								// Adjust Left Of Drawing Rect
	m_rLinkArea.top = iSpaceY;								// Adjust Top Of Drawing Rect
	m_rLinkArea.bottom = ( szExtent.cy + ( iSpaceX * 2 ) );	// Adjust Bottom Of Drawing Rect
	m_rLinkArea.right = ( szExtent.cx + ( iSpaceY * 2 ) );	// Adjust Right Of Drawing Rect
	m_rLinkArea.InflateRect( iSpaceX / 2 , iSpaceY / 2 );	// Inflate For Focus Rectangle

	dcDC.SetBkColor( m_crBackground );						// Set Background Color
	dcDC.ExtTextOut( iSpaceX, iSpaceY, ETO_OPAQUE, &rClient, 
			m_sDisplay, NULL );								// Draw Control's Text
	if( GetFocus() == this ) 								// If We Are Focused
	{
		dcDC.DrawFocusRect( &m_rLinkArea );					// Draw The Focus Rectangle
	}
	dcDC.RestoreDC( iDCState );								// Restore DC State
	
	ValidateRect( &rClient );								// Mark Drawing Area As Valid

	return;													// Done!
}


BOOL	CJRTSLinkCtrl::PreTranslateMessage( MSG *pMsg ) 
{
	if( !( GetStyle() & WS_DISABLED ) )						// If Control Is NOT Disabled
	{
		m_ttToolTips.Activate( ( m_dwStyle & 
				LCS_TOOLTIPS ) ? TRUE : FALSE );			// Enable/Disable ToolTip As Required
		m_ttToolTips.RelayEvent( pMsg );					// Relay Message
	}
	return( CWnd::PreTranslateMessage( pMsg ) );			// Do Default
}


void CJRTSLinkCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
{
	if( GetStyle() & WS_DISABLED )							// If Control Is Disabled
	{
		return;												// Stop Here
	}
	if( m_rLinkArea.PtInRect( point ) )						// If Point Inside Of Link Proper
	{
		m_dwStyle |= LCS_I_PREDRAG;							// Turn On PreDrag Flag
		m_ptPreDrag = point;								// Store Drag Origin
	}
	else													// If Not
	{
		m_dwStyle &= ~LCS_I_PREDRAG;						// Turn Off PreDrag Flag
	}
	m_dwStyle |= LCS_I_MDOWNONCLIENT;						// Set Mouse-Down-In-Client-Area Flag

	SetFocus();												// Focus The Control
	SetCapture();											// Capture Mouse Mesages

	return;													// Done!
}


void CJRTSLinkCtrl::OnLButtonUp(UINT nFlags, CPoint point) 
{
	if( GetStyle() & WS_DISABLED )							// If Control Is Disabled
	{
		return;												// Stop Here
	}
	CRect	rClient;

	GetClientRect( &rClient );								// Get Client Rect
	if( ( m_dwStyle & LCS_I_MDOWNONCLIENT ) &&				// If Over Client Area (Captured)
			( rClient.PtInRect( point ) ) )					// And Mouse Is Still Over Client Area
	{
		Activate();											// Activate The Link
	}
	m_dwStyle &= ~LCS_I_PREDRAG;							// Turn Off PreDrag Flag
	m_dwStyle &= ~LCS_I_TRACKING;							// Turn Off Tracking Flag
	m_dwStyle &= ~LCS_I_MDOWNONCLIENT;						// Turn Off MDownOnClient Flag

	ReleaseCapture();										// Release Capture
	
	return;													// Done!
}


void CJRTSLinkCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	if( GetStyle() & WS_DISABLED )							// If Control Is Disabled
	{
		return;												// Stop Here
	}
	if( GetFocus() == this )
	{
		if( nChar == VK_RETURN )							// If <RETURN> Hit
		{
			Activate();										// Trigger Activation Function
		}
	}
	return;													// Done!
}


void CJRTSLinkCtrl::PreSubclassWindow() 
{
	CWnd::PreSubclassWindow();

	Initialize();											// Initialize The Control

	return;													// Done!
}


BOOL	CJRTSLinkCtrl::Create( LPCTSTR lpszClassName, LPCTSTR lpszWindowName, 
				DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, 
				CCreateContext* pContext ) 
{
	BOOL	bStatus = CWnd::Create( lpszClassName, 
					lpszWindowName, dwStyle, rect, 
					pParentWnd, nID, pContext );			// Do Default

	Initialize();											// Initialize The Control

	return( bStatus );
}


void CJRTSLinkCtrl::OnMouseMove(UINT nFlags, CPoint point) 
{
	if( GetStyle() & WS_DISABLED )							// If Control Is Disabled
	{
		return;												// Stop Here
	}
	if( !( m_dwStyle & LCS_I_TRACKING ) )					// If Not Currently Tracking
	{
		TRACKMOUSEEVENT	tmeTME;

		tmeTME.cbSize = sizeof( TRACKMOUSEEVENT );			// Init Size
		tmeTME.dwFlags = ( TME_LEAVE | TME_HOVER );			// Init Flags
		tmeTME.hwndTrack = m_hWnd;							// Init Tracking Window
		tmeTME.dwHoverTime = HOVER_DEFAULT;					// Set Hover Time To System Default

		_TrackMouseEvent( &tmeTME );						// Start Tracking
		m_dwStyle |= LCS_I_TRACKING;						// Set Tracking Flag
		SendNotify( NMLC_MOUSEENTER, 0 );					// Send Notification Message
	}
	if( m_dwStyle & LCS_I_TRACKING )						// If Tracking
	{
		RedrawWindow( NULL, NULL, ( RDW_INVALIDATE | 
				RDW_UPDATENOW ) );							// Trigger A Non-Erasing Redraw
	}
	if( m_dwStyle & LCS_I_PREDRAG )							// If In Pre-Drag Mode
	{
		int	iDragX = ::GetSystemMetrics( SM_CXDRAG );		// X-Delta To Begin A Drag Operation
		int	iDragY = ::GetSystemMetrics( SM_CYDRAG );		// Y-Delta To Begin A Drag Operation
		int	iXDiff = ::abs( ( m_ptPreDrag.x - point.x ) );	// X Delta Movement
		int	iYDiff = ::abs( ( m_ptPreDrag.y - point.y ) );	// Y Delta Movement

		if( ( iXDiff >= iDragX ) || ( iYDiff >= iDragY ) )	// If We Moved Far Enough For A Drag To Begin
		{
			BOOL	bContinue = FALSE;

			if( m_dwStyle & LCS_I_RDRAG )					// If A RDrag
			{
				bContinue = SendNotify( NMLC_BEGINRDRAG, 
						TRUE );								// Send RDrag Notification Message
			}
			else											// If A Normal (Left) Drag
			{
				bContinue = SendNotify( NMLC_BEGINDRAG, 
						TRUE );								// Send Drab Notification Message
			}
			if( !bContinue )								// If Returned With FALSE
			{												
				m_dwStyle &= ~LCS_I_PREDRAG;				// Turn Off PreDrag Flag
				m_dwStyle &= ~LCS_I_RDRAG;					// Turn Off RDrag Style
				return;										// Cancel Drag Operation
			}
			COleDataSource	odsData;

			if( m_dwStyle & LCS_I_RDRAG )					// If A RDrag
			{
				SendNotify( NMLC_ENDRDRAG, 
						odsData.DoDragDrop(
						( DROPEFFECT_COPY | 
						DROPEFFECT_MOVE | DROPEFFECT_LINK | // Execute The D&D, 
						DROPEFFECT_SCROLL ) ) );			// Notify Parent Of Results
			}
			else											// If A Normal (Left) Drag
			{
				HGLOBAL	hGlobal = ::GlobalAlloc( 
								( GMEM_SHARE | 
								GMEM_ZEROINIT ), 4096 + 1 );// Allocate Memory For Target
				LPSTR	cpURL = (LPSTR)::GlobalLock( 
								hGlobal );
				
				if( !cpURL )								// If Allocation Failed
				{
					MessageBeep( MB_ICONEXCLAMATION );		// Beep At User
					m_dwStyle &= ~LCS_I_PREDRAG;			// Turn Off PreDrag Flag
					m_dwStyle &= ~LCS_I_TRACKING;			// Turn Off Tracking Flag
					m_dwStyle &= ~LCS_I_MDOWNONCLIENT;		// Turn Off MDownOnClient Flag
					m_dwStyle &= ~LCS_I_RDRAG;				// Turn Off RDrag Style
			
					return;									// Stop Here
				}
				ReleaseCapture();							// Release Mouse Capture
				::_tcsncpy( cpURL, m_sTarget.GetLength() ? 
						m_sTarget : m_sDisplay, 4096 );		// Copy Target Over
				cpURL[ 4096 ] = _T( '\0' );					// PTerminate Target
				::GlobalUnlock( hGlobal );					// Unlock GMemory
				odsData.CacheGlobalData( 
						CLIPFORMAT( CF_SHELLURL ), 
						hGlobal );							// Prepare ODS Object
				SendNotify( NMLC_ENDDRAG, 
						odsData.DoDragDrop( 				// Execute The D&D, 
						( DROPEFFECT_LINK | 
						DROPEFFECT_SCROLL ) ) );			// Notify Parent Of Results
			}
			m_dwStyle &= ~LCS_I_PREDRAG;					// Turn Off PreDrag Flag
			m_dwStyle &= ~LCS_I_TRACKING;					// Turn Off Tracking Flag
			m_dwStyle &= ~LCS_I_MDOWNONCLIENT;				// Turn Off MDownOnClient Flag
			m_dwStyle &= ~LCS_I_RDRAG;						// Turn Off RDrag Style
		}
	}
	return;													// Done!
}


void CJRTSLinkCtrl::OnKillFocus(CWnd* pNewWnd) 
{
	if( m_dwStyle & LCS_I_TRACKING )						// If Tracking
	{
		TRACKMOUSEEVENT	tmeTME;

		ReleaseCapture();									// Release Mouse Capture
		tmeTME.cbSize = sizeof( TRACKMOUSEEVENT );
		tmeTME.dwFlags = TME_CANCEL;
		tmeTME.hwndTrack = m_hWnd;
		tmeTME.dwHoverTime = 0;

		_TrackMouseEvent( &tmeTME );						// Cancel Tracking
		m_dwStyle &= ~LCS_I_PREDRAG;						// Turn Off PreDrag Flag
		m_dwStyle &= ~LCS_I_TRACKING;						// Turn Off Tracking Flag
		m_dwStyle &= ~LCS_I_MDOWNONCLIENT;					// Turn Off MDownOnClient Flag

		RedrawWindow();										// Redraw Entire Control
	}
	SendNotify( NMLC_KILLFOCUS, 0 );						// Send Notification Message

	return;													// Done!
}


BOOL CJRTSLinkCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
{
	if( nHitTest == HTCLIENT )								// If in Our Client Area
	{
		if( ms_hCursor )									// If Cursor Obtained
		{
			::SetCursor( ms_hCursor );						// Set The Cursor
			return( TRUE );									// Done!
		}
	}
	return( FALSE );										// Did Not Set The Cursor
}


BOOL CJRTSLinkCtrl::OnEraseBkgnd(CDC* pDC) 
{
	return( FALSE );										// All Erasing Handled In Painting...
}


void CJRTSLinkCtrl::OnEnable(BOOL bEnable) 
{
	if( bEnable )											// If We Are Enabling
	{
		ModifyStyle( WS_DISABLED, 0 );						// Remove Disabled Style
	}
	else													// If Disabling
	{
		ModifyStyle( 0, WS_DISABLED );						// Add Disabled Style
	}
	RedrawWindow();											// Redraw Control

	return;													// Done!
}


void CJRTSLinkCtrl::OnSetFocus(CWnd* pOldWnd) 
{
	CWnd::OnSetFocus(pOldWnd);

	SendNotify( NMLC_SETFOCUS, 0 );							// Send Notification Message
	
	return;													// Done!
}


void CJRTSLinkCtrl::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
	if( GetStyle() & WS_DISABLED )							// If Control Is Disabled
	{
		return;												// Stop Here
	}
	SendNotify( NMLC_DBLCLICK, 0 );							// Send Notification Message

	return;													// Done!
}


void CJRTSLinkCtrl::OnMButtonDblClk(UINT nFlags, CPoint point) 
{
	if( GetStyle() & WS_DISABLED )							// If Control Is Disabled
	{
		return;												// Stop Here
	}
	SendNotify( NMLC_MDBLCLICK, 0 );						// Send Notification Message
	m_dwStyle |= LCS_I_DBLCLICK;							// Add Double-Click Style
	
	return;													// Done!
}


void CJRTSLinkCtrl::OnMButtonDown(UINT nFlags, CPoint point) 
{
	SetFocus();												// Focus The Control
	SetCapture();											// Capture Mouse Mesages

	return;													// Done!
}


void CJRTSLinkCtrl::OnMButtonUp(UINT nFlags, CPoint point) 
{
	if( GetStyle() & WS_DISABLED )							// If Control Is Disabled
	{
		return;												// Stop Here
	}
	if( m_dwStyle & LCS_I_DBLCLICK )						// If Just Sent A Double-Click
	{
		m_dwStyle &= ~LCS_I_DBLCLICK;						// Remove Double-Click Style
	}
	else													// If Not
	{
		SendNotify( NMLC_MCLICK, 0 );						// Send Notification Message
	}
	ReleaseCapture();										// Release Capture

	return;													// Done!
}


void CJRTSLinkCtrl::OnRButtonDblClk(UINT nFlags, CPoint point) 
{
	if( GetStyle() & WS_DISABLED )							// If Control Is Disabled
	{
		return;												// Stop Here
	}
	SendNotify( NMLC_RDBLCLICK, 0 );						// Send Notification Message
	m_dwStyle |= LCS_I_DBLCLICK;							// Add Double-Click Style

	ReleaseCapture();										// Release Capture

	return;													// Done!
}


void CJRTSLinkCtrl::OnRButtonDown(UINT nFlags, CPoint point) 
{
	if( GetStyle() & WS_DISABLED )							// If Control Is Disabled
	{
		return;												// Stop Here
	}
	if( m_rLinkArea.PtInRect( point ) )						// If Point Inside Of Link Proper
	{
		m_dwStyle |= LCS_I_PREDRAG;							// Turn On PreDrag Flag
		m_dwStyle |= LCS_I_RDRAG;							// Turn On RDrag Flag

		m_ptPreDrag = point;								// Store Drag Origin
	}
	else													// If Not
	{
		m_dwStyle &= ~LCS_I_PREDRAG;						// Turn Off PreDrag Flag
		m_dwStyle &= ~LCS_I_RDRAG;							// Turn Off RDrag Flag
	}
	m_dwStyle |= LCS_I_MDOWNONCLIENT;						// Set Mouse-Down-In-Client-Area Flag

	SetFocus();												// Focus The Control
	SetCapture();											// Capture Mouse Mesages

	return;													// Done!
}


void CJRTSLinkCtrl::OnRButtonUp(UINT nFlags, CPoint point) 
{
	if( GetStyle() & WS_DISABLED )							// If Control Is Disabled
	{
		return;												// Stop Here
	}
	if( m_dwStyle & LCS_I_DBLCLICK )						// If Just Sent A Double-Click
	{
		m_dwStyle &= ~LCS_I_DBLCLICK;						// Remove Double-Click Style
	}
	else													// If Not
	{
		SendNotify( NMLC_RCLICK, 0 );						// Send Notification Message
	}
	ReleaseCapture();										// Release Capture
	
	return;													// Done!
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

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

Share

About the Author

Pablo Yabo
Technical Lead http://www.nektra.com
Argentina Argentina
Pablo Yabo is a Software Developer since he was young, specialized in system internals.
In 2003 years ago founded with Sebastian Wain a Company named Nektra specialized in Outlook Express and Outlook Plugin Development.
Now there is a new Windows Live Mail API 2011 / 2009 that works on all the platforms Windows 7, Vista and XP
Follow on   Twitter

| Advertise | Privacy | Mobile
Web02 | 2.8.140916.1 | Last Updated 27 Mar 2006
Article Copyright 2004 by Pablo Yabo
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid