你好,欢迎来到电脑编程技巧与维护杂志社! 杂志社简介广告服务读者反馈编程社区  
合订本订阅
 
 
您的位置:杂志经典 / 网络与通信
全屏取色功能的钩子实现
 

关于全屏取色功能,网络上有很多关于如何实现的文章,但这些文章所讲的都是同出一辙,都是利用几个API来实现,其实现步骤如下:1、用API GetCursorPos来获得当前鼠标的位置坐标;2、用API GetDC来获取桌面DC3、用API GetPixel获得当前鼠标所处位置的颜色值。

以上就是用API实现全屏取色的过程。读者从中可以看出其实现很简单,但用此种方法实现过全屏取色功能的读者都知道,其实这种方法用起来不太方便。首先,这种方法在进行取色时必须一直按着鼠标,直到取得满意的颜色才松手。如果取色时间过长,对于用户来说,这确实不是一件好事。其次,在完成取色而松开鼠标时,往往容易造成鼠标的轻微移动而致使所取得的颜色发生改变,从而不得不重新进行一次全屏取色。对于程序员来说,其程序的目的就是让用户尽可能的方便,显然这种全屏取色方法不是程序员所期望的。

针对此种方法的局限性,笔者认为用Windows钩子中的鼠标钩子来实现全屏取色更为方便。采用鼠标钩子进行全屏取色的步骤如下:1、主程序向实现鼠标钩子的DLL发送全屏取色指令;2、鼠标钩子DLL获取全屏取色指令,并执行全屏取色的相应指令;3、用户移动鼠标时,鼠标钩子DLL将当前鼠标位置的颜色值发送给主程序;4、主程序接收鼠标钩子DLL发送过来的颜色值并进行显示。

关于Windows钩子的使用,网络上有很多资料,读者可以上网搜索一下,我这里就不多重述了。应用程序与DLL共享数据有多种方法,比如利用内存映像文件共享数据、用消息WM_COPYDATA来传送数据等。考虑到程序的简洁性与方便性,我在这里使用Windows消息WM_COPYDATA来进行数据的传送,关于Windows消息WM_COPYDAT的相关说明可参考微软的MSDN,我这里不再重述。

为了让读者对其实现有更深入的理解,以下给出了全部源代码,这些源代码在WindowsXP下的Borland C++ Builder 6.0英文版编译通过,其生成的文件有两个:Test.exe为主程序,MouseHook.dll为实现全屏取色的鼠标钩子DLL

 

//-------------------------MouseHook.DLL的源程序------------------------------
#include <vcl.h>
#include <windows.h>
#pragma hdrstop
//-------------------------------------------------------------------------
//   Important note about DLL memory management when your DLL uses the
//   static version of the RunTime Library:
//
//   If your DLL exports any functions that pass String objects (or structs/
//   classes containing nested Strings) as parameter or function results,
//   you will need to add the library MEMMGR.LIB to both the DLL project and
//   any other projects that use the DLL.  You will also need to use MEMMGR.LIB
//   if any other projects which use the DLL will be performing new or delete
//   operations on any non-TObject-derived classes which are exported from the
//   DLL. Adding MEMMGR.LIB to your project will change the DLL and its calling
//   EXE's to use the BORLNDMM.DLL as their memory manager.  In these cases,
//   the file BORLNDMM.DLL should be deployed along with your DLL.
//
//   To avoid using BORLNDMM.DLL, pass string information using "char *" or
//   ShortString parameters.
//
//   If your DLL uses the dynamic version of the RTL, you do not need to
//   explicitly add MEMMGR.LIB as this will be done implicitly for you
//---------------------------------------------------------------------------
#pragma argsused
HHOOK       MouseHook = NULL;       // 钩子句柄
HINSTANCE   DLLInst = NULL;         // DLL实例
HINSTANCE   AppInst = NULL;         // 调用DLL应用程序的实例
COPYDATASTRUCT  *CopyData;          // 消息WM_COPYDATA所传送的数据
typedef struct      // 颜色值结构
{
    unsigned int    Red;
    unsigned int    Green;
    unsigned int    Blue;
}COLORINFO, *LPCOLORINFO;
COLORINFO   ColorInfo;
//-------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
    if(DLLInst == NULL) DLLInst = hinst;
 
    if(reason == DLL_PROCESS_ATTACH)        // 装载DLL
    {
        CopyData = new COPYDATASTRUCT;
        AppInst = FindWindow("TForm1", "Form1"); // 寻找调用此DLL的目标窗体
    }
    else if(reason == DLL_PROCESS_DETACH)   // 卸载DLL
    {
        delete CopyData;
    }
    return 1;
}
extern "C" __declspec(dllexport) void __stdcall DisableMouseHook(void)
{
    if(MouseHook != NULL)
    {
        UnhookWindowsHookEx(MouseHook);         // 卸掉钩子
        MouseHook = NULL;
    }
}
//-------------------------------------------------------------------------
LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    if(nCode == HC_ACTION)
    {
        if(wParam == WM_MOUSEMOVE)      // 如果移动鼠标则进行处理
        {
            MOUSEHOOKSTRUCT *l=(MOUSEHOOKSTRUCT *)lParam;   // 获得鼠标信息
            TColor Color = (TColor)GetPixel(GetDC(0), l->pt.x, l->pt.y);    
// 获得当前位置的颜色值
            ColorInfo.Red = GetRValue(Color);       // 分别得到当前位置颜色//值的RGB
            ColorInfo.Green = GetGValue(Color);
            ColorInfo.Blue = GetBValue(Color);
            CopyData->dwData = 1;                   // 本程序中用来标志当前//取色的状态,0表示停止取色,1表示进行取色
            CopyData->cbData = sizeof(COLORINFO);   // 所传送数据的大小
            CopyData->lpData = &ColorInfo;          // 所传送的数据
            SendMessage(AppInst, WM_COPYDATA, (WPARAM)NULL, (LPARAM)CopyData);  // 发送数据
        }
        else if(wParam == WM_LBUTTONUP) // 如果按下鼠标左键则停止钩子
        {
            CopyData->dwData = 0;   // 停止取色标志
            CopyData->cbData = sizeof(CopyData->dwData);
            CopyData->lpData = NULL;
            SendMessage(AppInst, WM_COPYDATA, (WPARAM)NULL, (LPARAM)CopyData);  
        }
    }
    return(CallNextHookEx(MouseHook, nCode, wParam, lParam));
}
//-------------------------------------------------------------------------extern "C" __declspec(dllexport) void __stdcall EnableMouseHook(void)
{
    if(MouseHook == NULL)
    {
   MouseHook = SetWindowsHookEx(WH_MOUSE, (HOOKPROC)MouseHookProc, DLLInst, 0);    // 安装钩子
    }
}
//-------------------------------------------------------------------------
以下是主程序的头文件源代码:
//----------------------------TestUnit.H源代码----------------------------
#ifndef TestUnitH
#define TestUnitH
//---------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <Buttons.hpp>
#include <ExtCtrls.hpp>
//---------------------------------------------------------------------
typedef void (__stdcall *ENABLEMOUSEHOOK)(void);    // MouseHook.dll
//里导出函数的声明
typedef void (__stdcall *DISABLEMOUSEHOOK)(void);
typedef struct      // 颜色值结构
{
    unsigned int    Red;
    unsigned int    Green;
    unsigned int    Blue;
}COLORINFO, *LPCOLORINFO;
//---------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
    TButton *Button2;
    TGroupBox *GroupBox1;
    TLabeledEdit *LabeledEdit1;
    TLabeledEdit *LabeledEdit2;
    TLabeledEdit *LabeledEdit3;
    TPanel *Panel1;
    TButton *Button1;
    void __fastcall Button2Click(TObject *Sender);
    void __fastcall Button1Click(TObject *Sender);
private:     // User declarations
    LPCOLORINFO         ColorInfo;
    HINSTANCE           DLLInst;            // 要调用的DLL实例
    ENABLEMOUSEHOOK     EnableMouseHook;    // 允许鼠标钩子的函数
    DISABLEMOUSEHOOK    DisableMouseHook;   // 停止鼠标钩子的函数
public:               // User declarations
    void __fastcall OnWMCopyData(TMessage &Message);    
// 处理WM_COPYDATA消息的函数
    BEGIN_MESSAGE_MAP   // WM_COPYDATA消息进行映射
        VCL_MESSAGE_HANDLER(WM_COPYDATA, TMessage, OnWMCopyData);
    END_MESSAGE_MAP(TForm);
    __fastcall TForm1(TComponent* Owner);
    __fastcall ~TForm1(void);
};
//---------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------
#endif
以下是主程序的具体实现源代码:
//----------------------TestUnit.cpp-----------------------------------
#include <vcl.h>
#pragma hdrstop
#include "TestUnit.h"
//---------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
COPYDATASTRUCT *CopyData;;
//---------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{          
    DLLInst = LoadLibrary("MouseHook.dll");     // 装入鼠标钩子DLL
    if(!DLLInst) PostQuitMessage(0);
    EnableMouseHook = (ENABLEMOUSEHOOK)GetProcAddress(DLLInst, "EnableMouseHook");
    DisableMouseHook = (DISABLEMOUSEHOOK)GetProcAddress(DLLInst, "DisableMouseHook");
    if(!(EnableMouseHook && DisableMouseHook)) PostQuitMessage(0);
    CopyData = new COPYDATASTRUCT;
}
//---------------------------------------------------------------------
__fastcall TForm1::~TForm1()
{
    FreeLibrary(DLLInst);   // 卸载鼠标钩子DLL
    delete CopyData;
}
//---------------------------------------------------------------------
void __fastcall TForm1::OnWMCopyData(TMessage &Message)
{
    CopyData = (COPYDATASTRUCT *)Message.LParam;    // 获得数据
    if(CopyData->dwData == 0)   // 停止鼠标钩子
    {
        DisableMouseHook();
    }
    else    
    {
        ColorInfo = (LPCOLORINFO)CopyData->lpData;  // 获得颜色值信息
       LabeledEdit1->Text = ColorInfo->Red;        // 显示相应的颜色信息
        LabeledEdit2->Text = ColorInfo->Green;
        LabeledEdit3->Text = ColorInfo->Blue;
        Panel1->Color = (TColor)RGB(ColorInfo->Red, ColorInfo->Green, ColorInfo->Blue);
    }
}
//---------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
    EnableMouseHook();      // 开始鼠标钩子
}
//---------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    PostQuitMessage(0);     // 退出程序
}
//---------------------------------------------------------------------
以上就是利用Windows鼠标钩子进行全屏取色的具体实现,读者在编译的时候,一定要记得把以下的两个编译开关关掉,否则编译的程序在没有装Borland C++ BuilderBorland Dephi的机子上不能运行:1、打开菜单Project下的Options窗体,把Packages页里的Build with runtime packages选项前的钩去掉;2、还是在Project下的Options窗体,把Linker页里的Use dynamic RTL选项前的钩去掉。
如果读者有兴趣,还可在这基础上进一步改进该程序,比如让程序进行全屏取色时,隐藏主程序的窗体,而出来一个显示颜色值的小框框(就像网络蚂蚁的显示下载框一样)。在具体实现的过程中,作者发现这么一个问题:当鼠标移到调用钩子DLL的主程序的标题栏时,得不到鼠标所处位置的颜色。对于这个问题,作者百思不得其解,如果哪位读者知道原因,麻烦与作者联系,作者在此表示感谢。
  推荐精品文章

·2024年2月目录 
·2024年1月目录
·2023年12月目录
·2023年11月目录
·2023年10月目录
·2023年9月目录 
·2023年8月目录 
·2023年7月目录
·2023年6月目录 
·2023年5月目录
·2023年4月目录 
·2023年3月目录 
·2023年2月目录 
·2023年1月目录 

  联系方式
TEL:010-82561037
Fax: 010-82561614
QQ: 100164630
Mail:gaojian@comprg.com.cn

  友情链接
 
Copyright 2001-2010, www.comprg.com.cn, All Rights Reserved
京ICP备14022230号-1,电话/传真:010-82561037 82561614 ,Mail:gaojian@comprg.com.cn
地址:北京市海淀区远大路20号宝蓝大厦E座704,邮编:100089