Click here to Skip to main content
15,881,812 members
Articles / Desktop Programming / MFC
Article

ColorCursor v. 2.2

Rate me:
Please Sign up or sign in to vote.
4.40/5 (4 votes)
22 Oct 20013 min read 99.2K   841   19   16
ColorCursor v. 2.1 pops up RGB values for all visible objects found on your desktop

Sample Image - ColorCursor.jpg

Introduction

ColorCursor 2.2 is a invisible tray-only application that pops up RGB values for all visible objects found on your desktop - pixel by pixel under the nose of your cursor (also known as its hot spot).

Starting cc.exe gives you a Woodstock or a Woodstock with a red line on top. This signals that ColorCursor is running/sleeping (1) - a normal icon means 'not-paused' and one with a red line means 'paused'. Interacting with it goes on from the Woodstock ctx. menu (2). Most items here are self explanatory I think.

On the menu you have several sections. The first one controls the way you log "color-pixels". ColorCursor enables you to track down mouse moves. This I refer to as recording. Nothing surprising about that (I'll come back to how it works in a moment). Next section sets up the format of the RBG-info. Third section controls the behavior of the ballooning.

It's all about hooking into other message queues of other processes. I've made a function for that in this dual workspace (one part for the app. and one for the hook-dll) called -

const bool HookInOtherMsgQueue();

And implementation like this -

const bool CCcFrameWnd::HookInOtherMsgQueue()
// Try to place a msg-hook under the queue of the window hoovered by the hotspot of the mouse to trap mouse events. It only happens if the mouse hoovers a new window.
{
	bool bNewHookNeeded = false;
	m_hWndMouseHoover_New = GetHWND_MouseHoover();
	if(m_hWndMouseHoover_Old)
	{
		// Hooked some window before.
		bNewHookNeeded = (m_hWndMouseHoover_New != m_hWndMouseHoover_Old);
	}
	else
	{
		// First hook.
		bNewHookNeeded = true;
		// Tell hook-dll who we are.
		FNSetHook_Owner *SetHook_Owner = (FNSetHook_Owner*)::GetProcAddress(m_hInstanceDll, _T("SetHook_Owner"));
		SetHook_Owner(m_hWnd);
	}
	if(bNewHookNeeded)
	{
		DWORD dwThreadId = 0,
			  dwProcessId = 0;
		dwThreadId = ::GetWindowThreadProcessId(m_hWndMouseHoover_New, &dwProcessId);
		if(dwThreadId)
		{
			HOOKPROC hHookProcAdr = (HOOKPROC)::GetProcAddress(m_hInstanceDll, _T("MouseTrap"));
			// Change hook proc.
			if(m_hHook)
				::UnhookWindowsHookEx(m_hHook);
			m_hHook = ::SetWindowsHookEx(WH_MOUSE, hHookProcAdr, m_hInstanceDll, dwThreadId);
			if(m_hHook)
			{
				// Tell hook-dll about new hook handle.
				FNSetHook *SetHook = (FNSetHook*)::GetProcAddress(m_hInstanceDll, _T("SetHook"));
				SetHook(m_hHook);
				// New hook set.
				return true;
			}
		}
		m_hWndMouseHoover_Old = m_hWndMouseHoover_New;
	}
	// No new hook set (old is reused (if any)).
	return false;
}

That's the far most interesting one in my (MFC) project. I don't say that this is indeed perfect but it works.

The point is that ColorCursor sets up a 100ms-timer when executed and not paused. On WM_TIMER events it asks if the mouse now hoovers a new window and, if so, it tries to hook into its msg. queue - tapping mouse events from it. What I'm interested here is only when L- and R- client and NonClient events go in for mouse-buttons. Now back to the timer -

void CCcFrameWnd::OnTimer(UINT uIdEvent) 
// The framework calls this member function after each interval specified in the SetTimer member function used to install a timer.
{
	CFrameWnd::OnTimer(uIdEvent);
	if(uIdEvent == sm_uIdTimer_Pop)
	{
		// If mouse hoovers a new window we try to hook into it now.
		HookInOtherMsgQueue();		
		// Show popup baloon.
		TTShow();
	}
}

TTShow(...) is called (TT == ToolTip). It prepares the balloon info for display and the overridden TTShow(const CString &cstrTTT) (TTT == ToolTipText) is called from it and pops the new TT only if (iff) it's now moved to a new pixel. To be able to show fast TT on demand I've made a by-proxy TT-class imitating a "real" TT (and 'proxy' because not based on native TT classes but on frame wnd's, in fact from ground up). This class along with other util. classes and functions (see lib. 'extra'), you get in addition to this project. I'll not go into details about how that works - you'll have to check that out yourself (or ask me).

Picture #3 shows you a balloon from the by-proxy class. Picture #4 is part of a RGB-log. To avoid stupid problems I let the app. go into a forced pause state on showing the log. Perhaps you can do better - forgive...

I've made the CCcFrameWnd::MouseTrap(...) event handler catch and filter the events I'll like to respond. A counterpart to it initiates it all inside the hook-dll -

LRESULT CALLBACK MouseTrap(int iCode, WPARAM wParam, LPARAM lParam)
// Call owner on interesting msg.
{
	if(iCode == HC_ACTION)
	{
		HWND hWnd = ::FindWindow(NULL, I_Constant_Title);
		if(hWnd && ::IsWindow(hWnd))
		{
			::PostMessage(hWnd, WM_MGSTRAP, wParam, lParam);
		}
	}
	return ::CallNextHookEx(g_hHook, iCode, wParam, lParam);
}

And naturally it all takes place because of the -

m_hHook = ::SetWindowsHookEx(WH_MOUSE, hHookProcAdr, m_hInstanceDll, dwThreadId);

In the CCcFrameWnd::HookInOtherMsgQueue() function.

One problem that I dit not solve was why the hWnd of the owner window did not match up the HWND of calling ::FindWindow(NULL, I_Constant_Title); in the hook-dll. This is not a huge problem though - but I can not understand why I can't tell my hook-dll about the owner hwnd, the hWnd to get the msg. next - cc in other words, from inside the hook-into-fct. (security obstruction?) I try to do that - but without much luck I'm afraid. Instead I have to use the title depended ::FindWindow(...) and that's a poor alternative I feel.

Enjoy - I'm looking forward to see what you all have to say about this.

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


Written By
Software Developer (Senior)
Denmark Denmark
c/c++/c# -developer.

Comments and Discussions

 
Generalhelp Pin
Kiethnt12-Nov-06 23:13
Kiethnt12-Nov-06 23:13 
Generalnot running Pin
26-Mar-02 4:23
suss26-Mar-02 4:23 
GeneralNice to see "Snuden" on CodeProject Pin
Christian Skovdal Andersen24-Oct-01 22:29
Christian Skovdal Andersen24-Oct-01 22:29 
GeneralHang & Crash Pin
24-Oct-01 4:17
suss24-Oct-01 4:17 
GeneralRe: Hang & Crash Pin
24-Oct-01 14:20
suss24-Oct-01 14:20 
GeneralRe: Hang & Crash Pin
Yawar Maajed25-Oct-01 11:37
Yawar Maajed25-Oct-01 11:37 
GeneralRe: Hang & Crash Pin
Yawar Maajed25-Oct-01 11:40
Yawar Maajed25-Oct-01 11:40 
Oops, my mistake, I am sorry, I thought this was a color mouse cursor, the program is doing exactly what it is meant to do, yes it shows the color value where the mouse is positioned.
Sorry, I should not have responded so quick, I thought it was a program that demonstrated example of loading image files in place of mouse cursors, since I have never done that myself, I have no idea how it is done.

Yawar

GeneralRe: Hang & Crash Pin
26-Oct-01 3:43
suss26-Oct-01 3:43 
GeneralRe: Hang & Crash Pin
Yawar Maajed26-Oct-01 7:03
Yawar Maajed26-Oct-01 7:03 
GeneralRe: Hang & Crash (final one :-) Pin
27-Oct-01 2:23
suss27-Oct-01 2:23 
QuestionReturning const bool ? What was the intent ? Pin
sahn024-Oct-01 2:11
sahn024-Oct-01 2:11 
AnswerRe: Returning const bool ? What was the intent ? Pin
24-Oct-01 14:15
suss24-Oct-01 14:15 
GeneralWindows 95/NT Pin
Paul C23-Oct-01 6:04
Paul C23-Oct-01 6:04 
GeneralRe: Windows 95/NT Pin
23-Oct-01 6:08
suss23-Oct-01 6:08 
Generalmissing files Pin
Kastellanos Nikos20-Jul-01 5:31
Kastellanos Nikos20-Jul-01 5:31 
GeneralRe: missing files Pin
20-Jul-01 14:18
suss20-Jul-01 14:18 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.