中文字幕天天躁日日躁狠狠躁,最近中文字幕大全免费版在线,最近2019免费中文字幕视频三,亚洲精品无码你懂的,亚洲国产精品成人精品小说

  • 相關(guān)軟件
    >VC開發(fā)實(shí)例 創(chuàng)建者:webmaster 更新時(shí)間:2005-07-02 01:23

    一、開發(fā)背景:

      我想大家都有過(guò)忙手忙腳最小化窗口(或關(guān)閉窗口)的經(jīng)歷吧!原因很簡(jiǎn)單??不想讓突如其來(lái)的老板、老媽、老婆看到我們電腦屏幕上正在顯示的游戲、日記、MM:-) 等屬于個(gè)人隱私的東東。

    如果能做一個(gè)程序在后臺(tái)運(yùn)行,當(dāng)我們發(fā)出一個(gè)特殊的輸入事件(我選擇了鼠標(biāo)左、右鍵同時(shí)按下)時(shí),該程序就迅速隱藏正在顯示的窗口,免去人工瞄準(zhǔn)并按下每個(gè)窗口右上方的那個(gè)小得可憐的的最小化按扭之苦了。當(dāng)危險(xiǎn)解除再利用這個(gè)特殊事件使隱藏的窗口恢復(fù)。

    這對(duì)于像我這樣小腦不太發(fā)達(dá)、心理素質(zhì)又不過(guò)硬而又經(jīng)常在老板的眼皮底下“懸崖騎馬”的同志們來(lái)說(shuō)是絕對(duì)有實(shí)戰(zhàn)意義的。于是我做了這個(gè)“魔高一丈”以實(shí)現(xiàn)上述功能!

    二、程序原理:

    首先,我們得能截獲鼠標(biāo)左、右鍵同時(shí)按下去這個(gè)事件??這并不難??設(shè)一個(gè)標(biāo)志變量當(dāng)鼠標(biāo)發(fā)出WM_LBUTTONDOWN并且又有WM_RBUTTONDOWN消息發(fā)出時(shí)把它置“1”罷了。

    而我要說(shuō)明的是,這個(gè)“同時(shí)按下”只是一種宏觀上的概念,鼠標(biāo)是不會(huì)同時(shí)發(fā)出兩個(gè)消息的。其次就是解決不管鼠標(biāo)位于任何窗口之上都能在程序里截獲(或者稱為監(jiān)聽更準(zhǔn)確)到鼠標(biāo)發(fā)出的消息并加以過(guò)濾的問(wèn)題了,這是很關(guān)鍵的。我用了鉤子船長(zhǎng)的那只鉤子(Hook),而且是全局的鼠標(biāo)鉤子,它給了我們跟操作系統(tǒng)溝通的一個(gè)機(jī)會(huì)。

    許多比較有神秘感的程序(比如金山詞霸的鼠標(biāo)取詞)都是用它實(shí)現(xiàn)的,稍后我將詳細(xì)解釋。最后就是剩下能得到可見的窗口的句柄(HANDLE)并根據(jù)其句柄顯示、隱藏窗口的問(wèn)題了,這也沒什么難的有現(xiàn)成的API函數(shù)??EnumWindows和ShowWindow。你可以先運(yùn)行一下我的程序(那個(gè)大五星,需要把它跟那個(gè)Mousehook.dll文件放在一個(gè)文件夾下)。當(dāng)鼠標(biāo)左右鍵一起按下時(shí)所有的窗口都隱藏了;再一次同時(shí)按下左右鍵又可恢復(fù)隱藏窗口;單擊任務(wù)欄右下角(托盤)的圖標(biāo)可隱藏或顯示本程序窗口。


    三、開發(fā)步驟:

    第0步、選用VC 6.0集成開發(fā)環(huán)境。
    第1步、由于建立全局鉤子必須把鉤子函數(shù)放在DLL里面,所以我們選擇MFC AppWizard(DLL)創(chuàng)建一個(gè)新的項(xiàng)目,命名為“Mousehook”,再選擇選擇MFC Extension DLL類型(為了方便嘛?。?BR>
      為什么必須把全局鉤子函數(shù)放在DLL里呢?這是因?yàn)橄到y(tǒng)會(huì)動(dòng)態(tài)地調(diào)用你所添加的全局鼠標(biāo)鉤子,所有窗口消息數(shù)都會(huì)由于你添加了鼠標(biāo)鉤子而引起系統(tǒng)處理(何為處理?調(diào)用鉤子函數(shù)也。)這必然需要操作系統(tǒng)能夠從一個(gè)東東里動(dòng)態(tài)地加入這段處理程序,而這個(gè)東東非DLL莫屬。

    第2步、在項(xiàng)目中加入Mousehook.h文件用以構(gòu)造一個(gè)鉤子類??CMousehook,具體如下:

    class AFX_EXT_CLASS CMousehook:public CObject
    {
    public:
    CMousehook();
    ~CMousehook();
    BOOL starthook();//封裝SetWindowsHookEx( int idHook, HOOK_PROC lpfn, HINSTANCE hMod,DWORD dwThreadID)用來(lái)安裝鉤子
    BOOL stophook(); //封裝UnhookWindowsHookEx( HHOOK hhk )用來(lái)卸載鉤子
    VOID SetCheck1(UINT i);//處理對(duì)話框的選擇鉤選框1
    VOID SetCheck2(UINT i);//處理對(duì)話框的選擇鉤選框2
    VOID SetCheck3(UINT i);//處理對(duì)話框的選擇鉤選框3
    static BOOL CALLBACK EnumWindowsProc(HWND hwnd,LPARAM lParam);//系統(tǒng)回調(diào)的鉤子函數(shù)
    VOID UseForExit();//退出程序時(shí)恢復(fù)所有隱藏窗口
    };

      這里我想特別地提一下EnumWindowsProc函數(shù)前的CALLBACK跟static,對(duì)于CALLBACK我想給大家一個(gè)特別江湖的解釋其就是:凡是由你設(shè)計(jì)而卻由Windows系統(tǒng)調(diào)用的函數(shù),統(tǒng)稱callback函數(shù)。這些函數(shù)都有一定的類型,以配合Windows的調(diào)用操作。??引用臺(tái)灣侯師傅的話。他還說(shuō),某些Windows API函數(shù)會(huì)要求以callback函數(shù)(的函數(shù)地址)作為其參數(shù)之一。

      我們這里用到的又比如 SetWindowsHookEx( int idHook, HOOK_PROC lpfn, HINSTANCE hMod,DWORD dwThreadID)的第二個(gè)參數(shù)。這種API通常會(huì)在進(jìn)行某種行為之后或滿足某種狀態(tài)的情況下調(diào)用其參數(shù)中的callback函數(shù)。

      又由于系統(tǒng)在調(diào)用callback函數(shù)的時(shí)候并不會(huì)借助任何對(duì)象去調(diào)用該callback函數(shù),所以在用類來(lái)封裝callback函數(shù)時(shí),需要用static來(lái)使callback函數(shù)能夠獨(dú)立于對(duì)象而又屬于類的成員函數(shù)。明白了不?(?。康厍蛉硕贾姥剑√珎宰鹆耍。?/P>

    第3步、在項(xiàng)目中加入Mousehook.cpp文件在CMousehook里封裝其中加入必要的共享數(shù)據(jù)以及SetWindowsHookEx、UnhookWindowsHookEx等函數(shù)??這些API函數(shù)具體的參數(shù)的類型跟作用解釋在程序代碼的注釋里有(網(wǎng)上也到處都有,我也是從網(wǎng)上摳下來(lái)的。一個(gè)聲音高叫著??當(dāng)然MSDN里也有。),而把它們寫在文章里就不免有騙取稿費(fèi)之嫌了。我只是想解釋一下為什么需要使用一個(gè)共享的數(shù)據(jù)段,如下:

    #pragma data_seg("mydata") //編譯器識(shí)別的指令用以在虛擬內(nèi)存中開辟一個(gè)數(shù)據(jù)段存放該指令下面的數(shù)據(jù)

    HINSTANCE glhInstance=NULL; //DLL實(shí)例(或者說(shuō)模塊)的句柄。
    HHOOK glhHook=NULL; //鼠標(biāo)鉤子的句柄。
    HWND GlobalWndHandle[100]={NULL,.....};//用來(lái)存放被隱藏的窗口的句柄,以數(shù)組的形式保存。
    //該數(shù)組必須初始化,原因見下文。我以“......”省略。
    UINT Global_i=0; //用以在循環(huán)中序列化窗口數(shù)組的變量。
    BOOL Condition1=0; //用以記錄左鍵按下或釋放的標(biāo)志變量。
    BOOL Condition2=0; //用以記錄右鍵按下或釋放的標(biāo)志變量。
    BOOL HideOrVisitableFlag=0; //用以標(biāo)識(shí)當(dāng)再次有左、右鍵同時(shí)按下的情況發(fā)生時(shí)是隱藏還是顯示窗口。
    BOOL Check1=0; //用來(lái)表示控件Check1狀態(tài)的標(biāo)志變量。
    BOOL Check2=0; //用來(lái)表示控件Check2狀態(tài)的標(biāo)志變量。
    BOOL Check3=0; //用來(lái)表示控件Check3狀態(tài)的標(biāo)志變量。

    #pragma data_seg() //與#pragma data_seg("mydata") 首尾呼應(yīng)表示該數(shù)據(jù)段的結(jié)束。


      加入上述數(shù)據(jù)段以后還應(yīng)在項(xiàng)目里插入一個(gè)“Mousehook.def”文件,用:"SECTIONS mydata READ WRITE SHARED"將mydata數(shù)據(jù)段設(shè)置為一個(gè)可讀寫的共享段。在程序里加入預(yù)編譯指令,或在開發(fā)環(huán)境的項(xiàng)目設(shè)置里也可以達(dá)到設(shè)置數(shù)據(jù)段屬性的目的,我就不一一贅述了。

      我前面講過(guò),系統(tǒng)通過(guò)調(diào)用放在DLL中的鉤子回調(diào)函數(shù)來(lái)實(shí)現(xiàn)全局鉤(鉤取所有窗口的鼠標(biāo)消息),操作系統(tǒng)對(duì)DLL的操作僅僅是把DLL映射到需要它的進(jìn)程的虛擬地址空間里去。也就是說(shuō),DLL函數(shù)中的代碼所創(chuàng)建的任何對(duì)象(包括變量)都?xì)w調(diào)用它的線程或進(jìn)程所有。

      “DLL在WIN32中什么都不擁有”??這句話很重要。比如我們?cè)贒LL里建立了一個(gè)變量a,而我們的這個(gè)DLL文件又被兩個(gè)進(jìn)程所調(diào)用,這兩個(gè)進(jìn)程的中都用到了a可這絕對(duì)是兩個(gè)不同存儲(chǔ)單元中存儲(chǔ)的兩個(gè)a,它們之間沒有絲毫的聯(lián)系。給其中一個(gè)賦值也絕對(duì)不會(huì)影響到另一個(gè)。


    而對(duì)于本程序的一些數(shù)據(jù)是需要在不同的進(jìn)程中保持唯一的(也可以說(shuō)是一致),比方說(shuō): HWND GlobalWndHandle[100]它是用來(lái)保存程序做了隱藏的窗口之句柄的數(shù)組。當(dāng)程序運(yùn)行,我在任意窗口A中同時(shí)按下了鼠標(biāo)左、右鍵,由于設(shè)置了鼠標(biāo)鉤子,系統(tǒng)會(huì)調(diào)用DLL中的鉤子處理函數(shù)截獲消息并加以處理,即把目前的可見窗口隱藏并把窗口句柄保存到GlobalWndHandle[100]數(shù)組中以備將來(lái)顯示之用。

      如果不把GlobalWndHandle[100]放到一個(gè)共享的數(shù)據(jù)段里,系統(tǒng)就會(huì)在目前我們截獲鼠標(biāo)消息的A窗口的進(jìn)程的地址空間里開辟HWND GlobalWndHandle[100]來(lái)存儲(chǔ)窗口句柄。這樣對(duì)于其他進(jìn)程就不能方便地得到這個(gè)進(jìn)程存入GlobalWndHandle[100]數(shù)組的數(shù)據(jù)了。這時(shí)只能將GlobalWndHandle[100]等需要跨進(jìn)程訪問(wèn)的變量數(shù)據(jù)放在一個(gè)共享的數(shù)據(jù)段里了。

      另外,需要特別注意??必須給這些變量賦初值(就象我在程序代碼里傻呼呼地寫了100個(gè)NULL一樣。你可以不初始化這個(gè)數(shù)組試驗(yàn)一下,有助于你理解我上面的話),否則編譯器會(huì)把沒有賦初始值的變量放在一個(gè)叫未被初始化的數(shù)據(jù)段中。

    第4步:編譯生成dll文件,并用MFC AppWizard(exe)建立一個(gè)基于對(duì)話框的項(xiàng)目,在里面添加一個(gè)名為“Mousehook.h”的頭文件其內(nèi)容與dll項(xiàng)目中的“Mousehook.h”文件一致,打開菜單的“Project Settings”對(duì)話框在“Link”選項(xiàng)標(biāo)簽的“Object/library modules”編輯框里填入Mousehook.lib(此文件是與dll一起生成的,當(dāng)編譯一個(gè)隱式調(diào)用dll的exe時(shí),lib文件起到提供dll引出函數(shù)接口地址的作用,如果此路徑設(shè)置不正確程序是無(wú)法進(jìn)行連接的)文件的存放路徑。這樣就可以放心使用dll里定義的CMousehook類的成員了。如下:

    1 在HideWindowDlg.h中加入#include "MouseHook.h"并在CHideWindowDlg中定義一個(gè)CMousehook類對(duì)象hook。
    2 在CHideWindowDlg::OnInitDialog()函數(shù)中加入hook.starthook()并初始化相關(guān)變量,這樣當(dāng)對(duì)話框初始時(shí)就會(huì)啟動(dòng)鼠標(biāo)鉤子。
    3 在CHideWindowDlg::~CHideWindowDlg()函數(shù)中加入hook.stophook()。用以釋放對(duì)話框?qū)ο髸r(shí)解除鼠標(biāo)鉤。

      為了不忽略讀者的智力水平我只對(duì)主要的代碼進(jìn)行了說(shuō)明,其余有關(guān)托盤、Check控件的部分代碼都比較傳統(tǒng)也沒什么好說(shuō)明的。最后,編譯成exe文件以后還須把Mousehook.dll文件拷貝到同exe相同的目錄下才能正確運(yùn)行exe。

    相關(guān)文章
    本頁(yè)查看次數(shù):