Blame | Last modification | View Log
// HyperLink.cpp : implementation file//// HyperLink static control. Will open the default browser with the given URL// when the user clicks on the link.//// Copyright Chris Maunder, 1997// Feel free to use and distribute.//// Thanks to Pål K. Tønder for auto-size and window caption changes.//// "GotoURL" function by Stuart Patterson// As seen in the August, 1997 Windows Developer's Journal.// Copyright 1997 by Miller Freeman, Inc.// All rights reserved.// Modified by Chris Maunder to use TCHARs instead of chars.#include "stdafx.h"#include "HyperLink.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endif#define TOOLTIP_ID 1/////////////////////////////////////////////////////////////////////////////// CHyperLink//////////////////////////////////////////////////////////////////////// CHyperLink::CHyperLink()//// Constructor, give the variables their initial values//////////////////////////////////////////////////////////////////////CHyperLink::CHyperLink(){m_crLinkColour = RGB( 0, 0, 238); //bluem_crVisitedColour = RGB( 85, 26, 139); //purplem_bVisited = FALSE; //hasn't been visited yet.m_bUnderline = TRUE; //underline the link?m_bAdjustToFit = TRUE; //resize the window to fit the text?m_strURL.Empty();}//////////////////////////////////////////////////////////////////////// CHyperLink::~CHyperLink()//// Destructor, delete our font//////////////////////////////////////////////////////////////////////CHyperLink::~CHyperLink(){//delete our font, if we have used itif ((HFONT)m_Font) m_Font.DeleteObject();}BEGIN_MESSAGE_MAP(CHyperLink, CStatic)//{{AFX_MSG_MAP(CHyperLink)ON_CONTROL_REFLECT(STN_CLICKED, OnClicked)ON_WM_CTLCOLOR_REFLECT()ON_WM_SETCURSOR()//}}AFX_MSG_MAPEND_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////// CHyperLink message handlers//////////////////////////////////////////////////////////////////////// BOOL CHyperLink::PreTranslateMessage( MSG* pMsg)//////////////////////////////////////////////////////////////////////////BOOL CHyperLink::PreTranslateMessage( MSG* pMsg){//pass a mouse message to our tool tip control for processingm_ToolTip.RelayEvent( pMsg);//default handling of messagesreturn CStatic::PreTranslateMessage( pMsg);}//////////////////////////////////////////////////////////////////////// HBRUSH CHyperLink::CtlColor(CDC* pDC, UINT nCtlColor)//////////////////////////////////////////////////////////////////////////HBRUSH CHyperLink::CtlColor(CDC* pDC, UINT nCtlColor){ASSERT(nCtlColor == CTLCOLOR_STATIC);// Set the approriate colourif (m_bVisited)pDC->SetTextColor( m_crVisitedColour);elsepDC->SetTextColor( m_crLinkColour);// Set underline font if requiredif (m_bUnderline){if (!(HFONT)m_Font){// Create font only once.LOGFONT lf;GetFont()->GetLogFont( &lf);lf.lfUnderline = TRUE;m_Font.CreateFontIndirect( &lf);}pDC->SelectObject( &m_Font);}// transparent text.pDC->SetBkMode( TRANSPARENT);return (HBRUSH)GetStockObject( NULL_BRUSH);}//////////////////////////////////////////////////////////////////////// BOOL CHyperLink::OnSetCursor( CWnd* pWnd, UINT nHitTest, UINT message)//////////////////////////////////////////////////////////////////////////BOOL CHyperLink::OnSetCursor( CWnd* pWnd, UINT nHitTest, UINT message){::SetCursor( m_hLinkCursor);return TRUE;}//////////////////////////////////////////////////////////////////////// void CHyperLink::PreSubclassWindow()//////////////////////////////////////////////////////////////////////////void CHyperLink::PreSubclassWindow(){//we want to get mouse clicks via STN_CLICKEDDWORD dwStyle = GetStyle();::SetWindowLong( m_hWnd, GWL_STYLE, dwStyle | SS_NOTIFY);//set the URL as the window textif (m_strURL.IsEmpty()) GetWindowText(m_strURL);// Check that the window text isn't empty. If it is, set it as the URL.CString strWndText;GetWindowText( strWndText);if (strWndText.IsEmpty()){//window and URL both empty. DUH!ASSERT( !m_strURL.IsEmpty());SetWindowText( m_strURL);}//adjust size of window to fit URL if necessaryPositionWindow();//load up the (standard) hyperlink cursorm_hLinkCursor = AfxGetApp()->LoadStandardCursor( IDC_ARROW);//create the tooltipCRect rect;GetClientRect( rect);m_ToolTip.Create( this);m_ToolTip.AddTool( this, m_strURL, rect, TOOLTIP_ID);CStatic::PreSubclassWindow();}/////////////////////////////////////////////////////////////////////////////// CHyperLink operations//////////////////////////////////////////////////////////////////////// void CHyperLink::SetURL(CString strURL)//////////////////////////////////////////////////////////////////////////void CHyperLink::SetURL( CString strURL){m_strURL = strURL;PositionWindow();m_ToolTip.UpdateTipText( strURL, this, TOOLTIP_ID);}//////////////////////////////////////////////////////////////////////// void CHyperLink::SetColours( COLORREF crLinkColour, COLORREF crVisitedColour)//////////////////////////////////////////////////////////////////////////void CHyperLink::SetColours( COLORREF crLinkColour, COLORREF crVisitedColour){m_crLinkColour = crLinkColour;m_crVisitedColour = crVisitedColour;Invalidate();}//////////////////////////////////////////////////////////////////////// void CHyperLink::SetVisited( BOOL bVisited /* = TRUE */)//// Link has been visited, mark the link//////////////////////////////////////////////////////////////////////void CHyperLink::SetVisited( BOOL bVisited /* = TRUE */){m_bVisited = bVisited;Invalidate();}//////////////////////////////////////////////////////////////////////// void CHyperLink::SetUnderline(BOOL bUnderline /* = TRUE */)//// Set link text to be underlined or not//////////////////////////////////////////////////////////////////////void CHyperLink::SetUnderline( BOOL bUnderline /* = TRUE */){m_bUnderline = bUnderline;Invalidate();}//////////////////////////////////////////////////////////////////////// void CHyperLink::SetAutoSize( BOOL bAutoSize /* = TRUE */)//// Property autosizing, set to true or false//////////////////////////////////////////////////////////////////////void CHyperLink::SetAutoSize( BOOL bAutoSize /* = TRUE */){m_bAdjustToFit = bAutoSize;PositionWindow();}//////////////////////////////////////////////////////////////////////// void CHyperLink::PositionWindow()//// Move and resize the window so that the window is the same size// as the hyperlink text. This stops the hyperlink cursor being active// when it is not directly over the text. If the text is left justified// then the window is merely shrunk, but if it is centred or right// justified then the window will have to be moved as well.//// Suggested by Pål K. Tønder//////////////////////////////////////////////////////////////////////void CHyperLink::PositionWindow(){if (!m_bAdjustToFit) return;//get the current window positionCRect rect;GetWindowRect( rect);CWnd* pParent = GetParent();if (pParent) pParent->ScreenToClient( rect);//get the size of the window textCString strWndText;GetWindowText(strWndText);CDC* pDC = GetDC();CSize Extent = pDC->GetTextExtent( strWndText);ReleaseDC( pDC);// Get the text justification via the window styleDWORD dwStyle = GetStyle();// Recalc the window size and position based on the text justificationif (dwStyle & SS_CENTERIMAGE)rect.DeflateRect(0, (rect.Height() - Extent.cy)/2);elserect.bottom = rect.top + Extent.cy;if (dwStyle & SS_CENTER)rect.DeflateRect( (rect.Width() - Extent.cx) / 2, 0);else{if (dwStyle & SS_RIGHT)rect.left = rect.right - Extent.cx;else // SS_LEFT = 0, so we can't test for it explicitlyrect.right = rect.left + Extent.cx;}// Move the windowSetWindowPos( NULL, rect.left, rect.top, rect.Width(),rect.Height(), SWP_NOZORDER);}/////////////////////////////////////////////////////////////////////////////// CHyperLink implementation//////////////////////////////////////////////////////////////////////// void CHyperLink::OnClicked()//// Hyperlink has been clicked by user//////////////////////////////////////////////////////////////////////void CHyperLink::OnClicked(){//visit URLint result = (int)GotoURL( m_strURL, SW_SHOW);//check if URL has been visitedm_bVisited = (result > HINSTANCE_ERROR);//something went wrong...if (!m_bVisited){MessageBeep( MB_ICONEXCLAMATION); // Unable to follow linkReportError( result);}elseSetVisited(); //repaint to show visited colour}//////////////////////////////////////////////////////////////////////// LONG CHyperLink::GetRegKey( HKEY key, LPCTSTR subkey, LPTSTR retdata)//////////////////////////////////////////////////////////////////////////LONG CHyperLink::GetRegKey( HKEY key, LPCTSTR subkey, LPTSTR retdata){HKEY hkey;LONG retval = RegOpenKeyEx( key, subkey, 0, KEY_QUERY_VALUE, &hkey);if (retval == ERROR_SUCCESS){long datasize = MAX_PATH;TCHAR data[MAX_PATH];RegQueryValue( hkey, NULL, data, &datasize);lstrcpy( retdata,data);RegCloseKey( hkey);}return retval;}//////////////////////////////////////////////////////////////////////// void CHyperLink::ReportError( int nError)//// report error to use, error strings are defined inside the function// and are not language dependent//////////////////////////////////////////////////////////////////////void CHyperLink::ReportError( int nError){CString str;switch (nError) {case 0: str = "The operating system is out\nof memory or resources."; break;case SE_ERR_PNF: str = "The specified path was not found."; break;case SE_ERR_FNF: str = "The specified file was not found."; break;case ERROR_BAD_FORMAT: str = "The .EXE file is invalid\n(non-Win32 .EXE or error in .EXE image)."; break;case SE_ERR_ACCESSDENIED: str = "The operating system denied\naccess to the specified file."; break;case SE_ERR_ASSOCINCOMPLETE: str = "The filename association is\nincomplete or invalid."; break;case SE_ERR_DDEBUSY: str = "The DDE transaction could not\nbe completed because other DDE transactions\nwere being processed."; break;case SE_ERR_DDEFAIL: str = "The DDE transaction failed."; break;case SE_ERR_DDETIMEOUT: str = "The DDE transaction could not\nbe completed because the request timed out."; break;case SE_ERR_DLLNOTFOUND: str = "The specified dynamic-link library was not found."; break;case SE_ERR_NOASSOC: str = "There is no application associated\nwith the given filename extension."; break;case SE_ERR_OOM: str = "There was not enough memory to complete the operation."; break;case SE_ERR_SHARE: str = "A sharing violation occurred. ";default: str.Format("Unknown Error (%d) occurred.", nError); break;}//add some explanationstr = "Unable to open hyperlink:\n\n" + str;//use a standard messagebox to display the messageAfxMessageBox( str, MB_ICONEXCLAMATION | MB_OK);}//#ifdef __cplusplus//extern "C" {//#endif//char *strstr( const char *string, const char *strCharSet );//unsigned char *_mbsstr( const unsigned char *string, const unsigned char *strCharSet );//#ifdef __cplusplus//}//#endif//////////////////////////////////////////////////////////////////////// HINSTANCE CHyperLink::GotoURL( LPCTSTR url, int showcmd)//// Go to an URL, uses ShellExecute to get IE running// ShellExecute opens or prints a specified file//////////////////////////////////////////////////////////////////////HINSTANCE CHyperLink::GotoURL( LPCTSTR url, int showcmd){TCHAR key[MAX_PATH + MAX_PATH];// First try ShellExecute()HINSTANCE result = ShellExecute( NULL, _T("open"), url, NULL,NULL, showcmd);// If it failed, get the .htm regkey and lookup the programif ((UINT)result <= HINSTANCE_ERROR){if (GetRegKey(HKEY_CLASSES_ROOT, _T(".htm"), key) == ERROR_SUCCESS){lstrcat( key, _T("\\shell\\open\\command"));if (GetRegKey( HKEY_CLASSES_ROOT,key,key) == ERROR_SUCCESS){TCHAR *pos;pos = _tcsstr( key, _T("\"%1\""));if (pos == NULL){// No quotes foundpos = _tcsstr( key, _T("%1")); //check for %1, without quotesif (pos == NULL) //no parameter at all...pos = key + lstrlen( key)-1;else*pos = '\0'; //remove the parameter}else*pos = '\0'; //remove the parameterlstrcat( pos, _T(" "));lstrcat( pos, url);//run the specified applicationresult = (HINSTANCE) WinExec( key,showcmd);}}}return result;}