这个工具是用来取屏幕中某一点的颜色,也就是得到这一点颜色的具体的RGB的值。类似的屏幕取色器其实挺多的,这个带源码,大家可以学习下。
因为需要hook鼠标move的消息,而且是全屏,所以需要使用全局钩子,也就是要将钩子功能写成动态链接库dll,
另外,因为我们需要得到某一点的颜色的值,所以很多时候我们得使用放大镜这个功能,而且MFC提供了CColorDialog功能类,这样我们就可以方便的提供调色板功能。很多截图软件所使用的也是同样的原理。
当时看了一点动态获取版本号的东西,所有这里面还有动态获取版本号的接口函数,就不细说了。
本工具纯属个人以前写着玩的,可能存在这样或那样的不足,欢迎交流原理性的东西,不欢迎纯问问题或编程风格类的交流。
开发环境:Win7 + VS2010(MFC)
废话少说,先上图,在上代码。
第一张是主界面,第二张是调色板界面,第三张是取色界面
主要代码马上就要列出来了,先说一下,代码中有很多注释,所以贴代码就不讲代码了
主界面的相关代码如下:
[cpp] view plaincopy
// 颜色按钮
void CRGBDlg::OnButtonCustomColor()
{
// TODO: Add your control notification handler code here
// CColorDialog colorDlg; // 调色板
COLORREF color;
if (m_pColorDlg != NULL && IDOK == m_pColorDlg->DoModal()) // 启动调色板
{
color = m_pColorDlg->GetColor(); // 获得选取的颜色
m_colorR.Format("%d", GetRValue(color)); // 格式化输出
m_colorG.Format("%d", GetGValue(color));
m_colorB.Format("%d", GetBValue(color));
DrawRGB();
UpdateData(FALSE);
}
}
// 取色按钮
void CRGBDlg::OnButtonGetColor()
{
ShowWindow(SW_HIDE); // 隐藏本窗口
m_pMagnifierDlg->StartHook(); // 启动hook
m_pMagnifierDlg->ShowWindow(SW_NORMAL); // 显示放大镜窗口
}
// hook 完成时的回调函数
LRESULT CRGBDlg::OnHookFinished(WPARAM wParam, LPARAM lParam)
{
if(lParam == TRUE)
{
// 从参数中读取RGB的值并且显示
m_colorR.Format("%d", GetRValue(wParam));
m_colorG.Format("%d", GetGValue(wParam));
m_colorB.Format("%d", GetBValue(wParam));
UpdateData(FALSE);
// if(m_pColorDlg != NULL)
// {
// COLORREF* pCustomColor = m_pColorDlg->GetSavedCustomColors();
// }
}
m_pMagnifierDlg->StopHook();
m_pMagnifierDlg->ShowWindow(SW_HIDE); // 显示放大镜窗口
// 画RGB所设置的颜色
DrawRGB();
ShowWindow(SW_NORMAL); // 正常显示窗口
::SetWindowPos(GetSafeHwnd(), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
::SetWindowPos(GetSafeHwnd(), HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
return TRUE;
}
放大镜启动mouse hook的代码
[cpp] view plaincopy
// 启动钩子
void CMagnifierDlg::StartHook()
{
SetWindowPos(0, 0, 0, MAGNIFIER_DEST_RANGE, MAGNIFIER_DEST_RANGE, SWP_NOZORDER | SWP_NOMOVE);
// 以下主要用于修正范围
GetClientRect(m_currClientRange);
INT offset = MAGNIFIER_DEST_RANGE - m_currClientRange.Width();
SetWindowPos(0, 0, 0, MAGNIFIER_DEST_RANGE + offset, MAGNIFIER_DEST_RANGE + offset, SWP_NOZORDER | SWP_NOMOVE);
m_isEnter = FALSE;
if(m_hook.StartHook(GetSafeHwnd(), WM_HOOK_MESSAGE)) // 如果启动钩子成功
{
GetClientRect(m_currClientRange); // 获得当前客户区,主要是ChangeDisplayPos里面需要用到客户区尺寸
m_isTopLeft = TRUE;
ChangeDisplayPos(); // 设置客户区位置,避免客户区在中间
SetTimer(ACTIVE_WINDOWS_TIMER, 250, NULL); // 启动自动激活的timer,避免客户区被别的程序覆盖
SetTimer(GET_RGB_VALUE_TIMER, 500, NULL);
}
else
{
PostMessage(WM_CLOSE);
}
}
放大镜放大部分代码
[cpp] view plaincopy
// 显示客户区域
void CMagnifierDlg::ShowClientArea()
{
HDC hDc = ::GetDC(NULL); // 获取屏幕DC
CDC *dc = GetDC();
//定义一个内存设备描述表对象(即后备缓冲区)
CDC memDc;
//定义一个位图对象
CBitmap memBitmap;
//建立与屏幕设备描述表(前端缓冲区)兼容的内存设备描述表句柄(后备缓冲区)
memDc.CreateCompatibleDC(NULL);
//这时还不能绘图,因为没有位图的设备描述表是不能绘图的
//下面建立一个与屏幕设备描述表(或者内存设备描述表)兼容的位图
memBitmap.CreateCompatibleBitmap(dc, m_currClientRange.Width(), m_currClientRange.Height());
//将位图选入到内存设备描述表
//只有选入了位图的设备描述表才有地方绘图,画到指定的位图上
CBitmap *pOldBit = memDc.SelectObject(&memBitmap);
//先用背景色将位图清除干净
memDc.FillSolidRect(0, 0,
m_currClientRange.Width(), m_currClientRange.Height(), BG_COLOR);
::StretchBlt(memDc.GetSafeHdc(),
0, 0,
m_currClientRange.Width(), m_currClientRange.Height(),
hDc,
m_currSourceRange.left,m_currSourceRange.top,
m_currSourceRange.Width(), m_currSourceRange.Height(),
SRCCOPY);
memDc.SetBkMode(TRANSPARENT);
memDc.SetTextColor(RGB(255,0,255));
if(!(memDc.DrawText(m_mousePosString, &m_mousePosStringRect, DT_LEFT | DT_VCENTER)
&& memDc.DrawText(m_rateString, &m_rateStringRect, DT_RIGHT | DT_VCENTER)
&& memDc.DrawText(m_mouseColorString, &m_mouseColorStringRect, DT_LEFT | DT_VCENTER)))
{
TRACE("DrawKeyText error %d /n", GetLastError());
}
if(m_isShowHelp)
{
if(m_helpInfo1 != "" && !memDc.DrawText(m_helpInfo1, &m_helpInfo1Rect, DT_RIGHT | DT_VCENTER))
TRACE("DrawHelpText error %d /n", GetLastError());
if(m_helpInfo2 != "" && !memDc.DrawText(m_helpInfo2, &m_helpInfo2Rect, DT_RIGHT | DT_VCENTER))
TRACE("DrawHelpText2 error %d /n", GetLastError());
}
else
{
ShowChildClientArea(hDc, &memDc);
}
// 画线
LONG hafelinewidth = (LONG)(m_rate / 2);
LONG linewidth = hafelinewidth * 2;
// 下面的x、y、cx、cy仅仅用作临时变量,并非真实的x、y
INT x = 0, y = MAGNIFIER_DEST_RANGE / 2 - hafelinewidth;
INT y2 = MAGNIFIER_DEST_RANGE / 2 + hafelinewidth + CURR_POS_RANGE;
INT cx = linewidth, cy = MAGNIFIER_DEST_RANGE / 2 - hafelinewidth - CURR_POS_RANGE;
// 画竖直线
// memDc.FillSolidRect(y, x, cx ,cy, LINE_COLOR);
// memDc.FillSolidRect(y, y2, cx ,cy, LINE_COLOR);
DrawLineRect(&memDc, y, x, cx ,cy);
DrawLineRect(&memDc, y, y2, cx ,cy);
// 画水平线
DrawLineRect(&memDc, x, y, cy ,cx);
DrawLineRect(&memDc, y2, y, cy ,cx);
// memDc.FillSolidRect(x, y, cy ,cx, LINE_COLOR);
// memDc.FillSolidRect(y2, y, cy ,cx, LINE_COLOR);
#if 0
// 画个圆
memDc.Ellipse(CRect(MAGNIFIER_DEST_RANGE / 2 - CURR_POS_RANGE, MAGNIFIER_DEST_RANGE / 2 - CURR_POS_RANGE,
MAGNIFIER_DEST_RANGE / 2 + CURR_POS_RANGE, MAGNIFIER_DEST_RANGE / 2 + CURR_POS_RANGE));
#endif
//将后备缓冲区中的图形拷贝到前端缓冲区
dc->BitBlt(0, 0, m_currClientRange.Width(), m_currClientRange.Height(), &memDc, 0, 0, SRCCOPY);
//绘图完成后的清理
memBitmap.DeleteObject();
memDc.DeleteDC();
/*::ReleaseDC(GetSafeHwnd(), dc); // 释放当前客户区dc*/
ReleaseDC(dc);
if (m_currWarningRange.PtInRect(m_mousePos)) // 如果当前点在触发切换区域内,则触发切换
{
ChangeDisplayPos();
}
::ReleaseDC(0, hDc); // 释放屏幕dc
}
还有个子放大区域的代码,和整个差不多,就不整了
鼠标hook的关键代码
[cpp] view plaincopy
LRESULT WINAPI MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
LPMOUSEHOOKSTRUCT pMouseHook=(MOUSEHOOKSTRUCT FAR *)lParam;
if (gHwnd != NULL)
{
PostMessage(gHwnd, gMessageId, wParam, POINTTOPOINTS(pMouseHook->pt));
TRACE("debug info isBlock = %d/n", gIsBlock);
if(gIsBlock)
{
return TRUE;
}
}
return CallNextHookEx(glhHook,nCode,wParam,lParam);
//继续传递消息
}
以上的代码就是此工具的关键点,涉及到钩子的安防,放大镜的实现。