Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

ColourGrabber2

0.00/5 (No votes)
5 Mar 2014 1  
Using Windows hooks to capture mouse action.

Introduction

I was working on another project when I discovered I wanted a particular colour for an HTML style class and I had no immediate means to discover the HTML colour value. I had previously created a colour picker application (ColourGrabber) and it accomplished what I needed. However, I noticed some shortcomings with the application and decided I’d like to resolve those. The primary deficiency was that the program was a dialog-based application and used SetCapture() to capture mouse input. Unfortunately, SetCapture() confines cursor position reporting to the application/parent window and thus I couldn’t provide a preview of the colour under the cursor. After a lot of trial and error, I discovered the hook functions. ColourGrabber2 resolves the problem.

Unfortunately, as soon as I upgraded my OS to Windows 8.1, ColourGrabber2 stopped working. The solution has been a closer examination of the hook functions.

Using the Code

This project begins with a dialog based program. The primary dialog class is called CColourGrabber2Dlg. Set up two global variables...

CColourGrabber2Dlg *pDialog=NULL;
HHOOK handleHook=NULL; 

...at the beginning of CColourGrabber2.cpp.

The next step was to create the hook function immediately following the two global variables. In the previously posted version, I used the hook type WH_JOURNALRECORD. Unfortunately, I discovered that the set hook call failed in Windows 8. However, by changing the call to the Low Level mouse hook, WH_MOUSE_LL, and then changing the mouse message handling function so that wParam and lParam are handled correctly, the problem is solved. wParam contains the specific mouse message such as WM_LBUTTONDOWN and WM_MOUSEMOVE and lParam is a pointer to an MSLLHOOKSTRUCT that provides location information. Therefore, the new code for MouseProc is:

LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam) { 
    CPoint ptLocation;
    
    MSLLHOOKSTRUCT * Msg = (MSLLHOOKSTRUCT *)lParam; 
    ptLocation = Msg->pt;
    if (wParam == WM_LBUTTONDOWN) 
    { 
        pDialog->GrabColour(ptLocation); 
    } 
    if (wParam == WM_MOUSEMOVE)
    { 
        pDialog->ShowCoordinates(ptLocation); 
    } 
    LRESULT result = CallNextHookEx(handleHook, nCode, wParam, lParam); 
    return result; 
 } 

Notice that this is very simple. The function determines the cursor position and then processes just two messages, WM_LBUTTONDOWN and MW_MOUSEMOVE. For each of these messages, a method belonging to CColourGrabber2Dlg is called.

In CColourGrabber2Dlg::InitDialog, make the dialog accessible to the MouseProc function:

pDialog = this;  

In CColourGrabber2::OnBnClickedPickColourButton, place the statements:

handleHook = SetWindowsHookEx(WH_MOUSE_LL, (HOOKPROC) MouseProc, GetModuleHandle(NULL), NULL); 

Now define the functions that will process the mouse information:

void CColourGrabber2Dlg::GrabColour(CPoint point)
{
    if (m_bGetPostion ) // this is a member variable set to true 
            // when the "Get Colour" button is clicked
    {
        CDC dcScreen ;
        dcScreen.CreateDC("DISPLAY", NULL, NULL, NULL);

        COLORREF crPixelColour = GetPixel(dcScreen.GetSafeHdc(), 
            point.x, point.y);
        // Do something with the information such as 
        // set a control’s background colour to the colour just
        // grabbed and report the position 

        ReleaseDC(&dcScreen);
        m_bGetPosition = false;
        UnhookWindowsHookEx(handleHook);
    }

and:

void CColourGrabber2Dlg::ShowCoordinates(CPoint point )
{
    if (m_bGetPostion)
    {
        CDC dcScreen ;
        dcScreen.CreateDC("DISPLAY", NULL, NULL, NULL);
        COLORREF crPixelColour  = GetPixel(dcScreen.GetSafeHdc(), 
            point.x, point.y);
        // Again do something with the information about the
        // position of the cursor as the mouse moves it such as
        // dynamically changing the text and background colour of
        // a static control.

        ReleaseDC(&dcScreen);
    }
}

Everything else in the project is for displaying and using the colour and position information. I hope others find this helpful.

Please also note that the project uses the Ultimate TCP-IP library which is not included with the source files.

Acknowledgements

History

  • Version 2.0 June 14, 2013: The move to using hooks provides a significant improvement to the user interface for a colour grabber.
  • Version 2.2 March 5, 2014: Version 2.0 did not work with Windows 8.1. Changes to the hook type (WH_MOUSE_LL from WH_JOURNALRECORD) and subsequent changes to the function processing the messages from the mouse have solved the problem.

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