Transforming Static Text Controls into Active Hyperlinks Using the Win32 API

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


Comments

  • Nike Aura Max+instagram, at one's desire you confine the color to step on your feet!

    Posted by madytreathy on 04/25/2013 02:31pm

    Recognize in 2008, if not earlier, when Nike launched winning of the self-assured shoe color projects, the slogan "Whiz Your Colours", "Nike PhotoiD" blueprint, [url=http://fossilsdirect.co.uk/glossarey.cfm]nike huarache free[/url] effect has not been as avid as expected. Deem, 2008 Canon IXUS 80 IS Digital file card arcade but purely 8 million pixels, Nokia, the mobile phone market is the one administration, NikeiD was advocate to color in the photos as a underpinning quest of sneakers excise color, although exciting, but does bother some. Instagram which cause this item hold up to ridicule and fundamental, Nike PHOTOiD homeopathic upgrade customization services, recently [url=http://markwarren.org.uk/goodbuy.cfm]nike free run uk[/url] released a unique plan. That such iD can you implement pictures as instagram account shoe color, little while put up Nike Breeze Max shoes and Nike Puff Max 1, Nike Air Max 90 953 options. Interested in children's shoes, you [url=http://northernroofing.co.uk/roofins.cfm]nike free run[/url] can every go's legitimate website photoid.Nike.com, in reckoning to browse other people's originative industry, or you can hear to upload your own instagram photo, base your own Nike Feeling Max.

    Reply
  • thank you

    Posted by marx on 02/21/2013 07:36am

    thank you very much.it is very good!

    Reply
  • Thanks

    Posted by 1111 on 10/03/2012 07:06am

    Great

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • 10 Rules that Make or Break Enterprise App Development Projects In today's app-driven world, application development is a top priority. Even so, 68% of enterprise application delivery projects fail. Designing and building applications that pay for themselves and adapt to future needs is incredibly difficult. Executing one successful project is lucky, but making it a repeatable process and strategic advantage? That's where the money is. With help from our most experienced project leads and software engineers, …

  • Live Event Date: September 10, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild". This loop of continuous delivery and continuous feedback is …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds