Transforming Static Text Controls into Active Hyperlinks Using the Win32 API

CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Transform any static text control:

Into an active hyperlink:

Environment: VC6, VC7, and likely others

In need of a quick hyperlink control in an About box, I noticed that CodeGuru had a couple of options available to MFC users. Unfortunately, I needed a solution that dealt directly with the Win32 API. Because I have benefited from CodeGuru in the past, I thought this would make a nice opportunity to contribute something of my own. With a little work, here’s what I put together.

It seems that a static text control is almost a hyperlink, but it needs four customizations:

  1. Clicking the text needs to open a browser window to the location specified by the text.
  2. The cursor needs to change from the standard arrow cursor to a pointing index finger when it moves over the control.
  3. The text in the control needs to be underlined when the cursor moves over the control.
  4. A hyperlink control needs to display text in a different color—black just won’t do.

The first customization can be done rather easily by changing the style of the static text control to include notifications to the parent window whenever the control is clicked. This style can be changed in the Visual C++ dialog editor, but it is just as easy to do from within the source code.


// Make sure the control will send notifications.

DWORD dwStyle = GetWindowLong(hwndCtl, GWL_STYLE);
SetWindowLong(hwndCtl, GWL_STYLE, dwStyle | SS_NOTIFY);

A simple call to ShellExecute() from within the parent window’s message handler can be used to browse to the desired location.


case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDC_SNAGGLEHOMEPAGE:
{
ShellExecute(hwnd, “open”,
“http://www.awesoftware.com/snaggle/default.htm”,
NULL, NULL, SW_SHOWNORMAL);
return TRUE;
}
}
break;
}

The second customization can be handled by subclassing the static text control and handling the WM_SETCURSOR message.


// Subclass the existing control.

WNDPROC pfnOrigProc = (WNDPROC) GetWindowLong(hwnd,
GWL_WNDPROC);
SetProp(hwnd, PROP_ORIGINAL_PROC, (HANDLE) pfnOrigProc);
SetWindowLong(hwnd, GWL_WNDPROC, (LONG) (WNDPROC)
_HyperlinkProc);

// Handle the WM_SETCURSOR message to use the desired cursor.

case WM_SETCURSOR:
{
// Because IDC_HAND is not available on all operating
// systems, we will load the arrow cursor if IDC_HAND is not
// present.

HCURSOR hCursor = LoadCursor(NULL, MAKEINTRESOURCE
(IDC_HAND));
if (NULL == hCursor)
{
hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
}
SetCursor(hCursor);
return TRUE;
}

After the static text control is subclassed, monitoring the WM_MOUSEMOVE message to see when the cursor travels into and out of the control is no problem at all. When the cursor comes in, we set an underline font for the control. When the cursor moves out, we set the font back to its original state. Now, there’s only one customization remaining.


// Create an underline version of the control’s font and
// store both fonts where we can get at them

HFONT hOrigFont = (HFONT) SendMessage(hwnd, WM_GETFONT, 0, 0);
SetProp(hwnd, PROP_ORIGINAL_FONT, (HANDLE) hOrigFont);

LOGFONT lf;
GetObject(hOrigFont, sizeof(lf), &lf);
lf.lfUnderline = TRUE;

HFONT hFont = CreateFontIndirect(&lf);
SetProp(hwnd, PROP_UNDERLINE_FONT, (HANDLE) hFont);

// Handle the WM_MOUSEMOVE message to set the appropriate font.

case WM_MOUSEMOVE:
{
if (GetCapture() != hwnd)
{
HFONT hFont = (HFONT) GetProp(hwnd, PROP_UNDERLINE_FONT);
SendMessage(hwnd, WM_SETFONT, (WPARAM) hFont, FALSE);
InvalidateRect(hwnd, NULL, FALSE);
SetCapture(hwnd);
}
else
{
RECT rect;
GetWindowRect(hwnd, &rect);

POINT pt = { LOWORD(lParam), HIWORD(lParam) };
ClientToScreen(hwnd, &pt);

if (!PtInRect(&rect, pt))
{
HFONT hFont = (HFONT) GetProp(hwnd, PROP_ORIGINAL_FONT);
SendMessage(hwnd, WM_SETFONT, (WPARAM) hFont, FALSE);
InvalidateRect(hwnd, NULL, FALSE);
ReleaseCapture();
}
}
break;
}

To change the text color in the control, we can catch the WM_CTLCOLORSTATIC message. However, we need to subclass the control’s parent to gain access to the message. After we have done that, we’re all set.


// Subclass the parent so we can color the controls as we desire.

HWND hwndParent = GetParent(hwnd);
if (NULL != hwndParent)
{
WNDPROC pfnOrigProc = (WNDPROC) GetWindowLong(hwndParent,
GWL_WNDPROC);
if (pfnOrigProc != _HyperlinkParentProc)
{
SetProp(hwndParent, PROP_ORIGINAL_PROC, (HANDLE)
pfnOrigProc);
SetWindowLong(hwndParent, GWL_WNDPROC, (LONG)
(WNDPROC) _HyperlinkParentProc);
}
}

// Set a flag on the control so we know what color it should be.
// This allows us to distinguish between static text controls.
// We need to decide what color the control should be.

SetProp(hwnd, PROP_STATIC_HYPERLINK, (HANDLE) 1);

// Handle the WM_CTLCOLORSTATIC message to change the color.
// We need to make sure the control is intended to be a
// hyperlink before changing the color.

case WM_CTLCOLORSTATIC:
{
HDC hdc = (HDC) wParam;
HWND hwndCtl = (HWND) lParam;

BOOL fHyperlink = (NULL != GetProp(hwndCtl,
PROP_STATIC_HYPERLINK));
if (fHyperlink)
{
LRESULT lr = CallWindowProc(pfnOrigProc, hwnd, message,
wParam, lParam);
SetTextColor(hdc, RGB(0, 0, 192));
return lr;
}

break;
}

Now, it’s a simple matter to transform any static text control into an active hyperlink. The included source code makes this all rather easy. A simple function call is all you need. Two functions are available to convert a static text control into a hyperlink.


BOOL ConvertStaticToHyperlink(HWND hwndCtl);
BOOL ConvertStaticToHyperlink(HWND hwndParent, UINT uiCtlId);

You can call one of these functions from within a dialog box’s WM_INITDIALOG message handler and everything should work fine.


case WM_INITDIALOG:
{
ConvertStaticToHyperlink(hwnd, IDC_SNAGGLEHOMEPAGE);
break;
}

To summarize, there are just two steps you need to take to quickly transform a static text control into an active hyperlink:

  1. Download the source code and include “Hyperlinks.cpp” and “Hyperlinks.h” in your application.
  2. From within your dialog’s OnInitDialog() (MFC) or WM_INITDIALOG handler (straight Win32 API), call:


ConvertStaticToHyperlink(GetSafeHwnd(), IDC_MY_HYPERLINK_CTL);
// MFC

– or –


ConvertStaticToHyperlink(hwndDialog, IDC_MY_HYPERLINK_CTL);
// Win32

That’s all there is to it! This example could certainly be extended to have the static control automatically open the Web page, so the control’s parent wouldn’t need to do it, but I will leave that for another CodeGuru-ite to implement.

Downloads


Download source – 2 Kb

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read