乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      HOOK (轉(zhuǎn))

       3D建模仿真 2012-05-03

      利用鍵盤(pán)鉤子開(kāi)發(fā)按鍵發(fā)音程序
      作者:GDGF

      一、前言
      一日,看見(jiàn)我媽正在用電腦練習(xí)打字,頻頻低頭看鍵盤(pán),我想:要是鍵盤(pán)能發(fā)音的話,不就可以方便她養(yǎng)成"盲打"的好習(xí)慣嗎?光想不做可不行,開(kāi)始行動(dòng)(您可千萬(wàn)別急著去拿工具箱啊^_^)...
      按鍵能發(fā)音,其關(guān)鍵就是讓程序能夠知道當(dāng)前鍵盤(pán)上是哪個(gè)鍵被按下,并播放相應(yīng)的聲音,自己的程序當(dāng)然不在話下,那么其它程序當(dāng)前按下哪個(gè)鍵如何得知呢?利用鍵盤(pán)鉤子便可以很好地解決。

      下載本文的全部源代碼 大小:552K

      二、掛鉤(HOOK)的基本原理
      WINDOWS調(diào)用掛接的回調(diào)函數(shù)時(shí)首先會(huì)調(diào)用位于函數(shù)鏈?zhǔn)椎暮瘮?shù),我們只要將自己的回調(diào)函數(shù)置于鏈?zhǔn)祝摶卣{(diào)函數(shù)就會(huì)首先被調(diào)用。那么如何將我們自己的回調(diào)函數(shù)置于函數(shù)鏈的鏈?zhǔn)啄??函?shù)SetWindowsHookEx()實(shí)現(xiàn)的就是該功能。我們首先來(lái)看一下SetWindowsHookEx函數(shù)的原型:

      HHOOK SetWindowsHookEx(
        int idHook,       
        HOOKPROC lpfn,     
        HINSTANCE hMod,    
        DWORD dwThreadId  
      ); 
      第一個(gè)參數(shù):指定鉤子的類型,有WH_MOUSE、WH_KEYBOARD等十多種(具體參見(jiàn)MSDN)
      第二個(gè)參數(shù):標(biāo)識(shí)鉤子函數(shù)的入口地址
      第三個(gè)參數(shù):鉤子函數(shù)所在模塊的句柄;
      第四個(gè)參數(shù):鉤子相關(guān)函數(shù)的ID用以指定想讓鉤子去鉤哪個(gè)線程,為0時(shí)則攔截整個(gè)系統(tǒng)的消息。

      另外需要注意的是為了捕獲所有事件,掛鉤函數(shù)應(yīng)該放在動(dòng)態(tài)鏈接庫(kù)DLL中。

      三、具體實(shí)現(xiàn)

      理論的話就不多說(shuō)了,運(yùn)行VC++6.0,新建一個(gè)MFC AppWizard(dll)工程,命名為Hook,使用默認(rèn)的創(chuàng)建DLL類型的選項(xiàng),也就是使用共享MFC DLL,點(diǎn)擊完成后開(kāi)始編寫(xiě)代碼:

      (1)在Hook.h中定義全局函數(shù)
      BOOL installhook(); //鉤子安裝函數(shù)
      LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);//掛鉤函數(shù)

      (2)在Hook.cpp文件的#endif下添加定義全局變量Hook的代碼:
      static HHOOK hkb=NULL;
      HINSTANCE hins; //鉤子函數(shù)所在模塊的句柄
      (3)添加核心代碼
      BOOL installhook()
      {
          hkb=SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)KeyboardProc,hins,0);
          return TRUE;
      }

      第一個(gè)參數(shù)指定鉤子的類型,因?yàn)槲覀冎挥玫芥I盤(pán)操作所以設(shè)定為WH_KEYBOARD;第二個(gè)參數(shù)將鉤子函數(shù)的入口地址指定為KeyboardProc,當(dāng)鉤子鉤到任何消息后便調(diào)用這個(gè)函數(shù),即當(dāng)不管系統(tǒng)的哪個(gè)窗口有鍵盤(pán)輸入馬上會(huì)引起KeyboardProc的動(dòng)作;第三個(gè)參數(shù)是鉤子函數(shù)所在模塊的句柄;最后一個(gè)參數(shù)是鉤子相關(guān)函數(shù)的ID用以指定想讓鉤子去鉤哪個(gè)線程,為0時(shí)則攔截整個(gè)系統(tǒng)的消息;
      現(xiàn)在,就開(kāi)始定義當(dāng)鍵盤(pán)上的鍵按下時(shí)程序要做什么了~
      KeyboardProc動(dòng)作:

      LRESULT CALLBACK KeyboardProc(int nCode,WPARAM wParam,LPARAM lParam)
      { 
          if(((DWORD)lParam&0x40000000) && (HC_ACTION==nCode))
          {
             switch(wParam) //鍵盤(pán)按鍵標(biāo)識(shí)
              {
              case ''1'':sndPlaySound("1.wav",SND_ASYNC);break; //當(dāng)數(shù)字鍵1被按下
               case ''2'':sndPlaySound("2.wav",SND_ASYNC);break;
              case ''3'':sndPlaySound("3.wav",SND_ASYNC);break;
              case ''4'':sndPlaySound("4.wav",SND_ASYNC);break;
              ....
              case ''A'':sndPlaySound("a.wav",SND_ASYNC);break; //當(dāng)字母鍵A被按下
               case ''B'':sndPlaySound("b.wav",SND_ASYNC);break;
              case ''C'':sndPlaySound("c.wav",SND_ASYNC);break;
              case ''D'':sndPlaySound("d.wav",SND_ASYNC);break;
              ....
              }
           }
           LRESULT RetVal = CallNextHookEx( hkb, nCode, wParam, lParam ); 
           return RetVal;
      }
      上面的代碼中我們用播放聲音做為按鍵被按下后的動(dòng)作,API函數(shù)sndPlaySound的第一個(gè)參數(shù)定義的聲音文件的絕對(duì)路徑(比如要播放C盤(pán)下的a.wav,就定義成"C:\\a.wav");第二參數(shù)定義播放模式,SND_ASYNC模式可以及時(shí)地釋放正在播放的聲音文件,立刻停止當(dāng)前聲音的播放轉(zhuǎn)去播放新的聲音,這樣在我們連續(xù)擊鍵時(shí)就不會(huì)有阻塞感了.為了執(zhí)行sndPlaySound函數(shù),必須在Hook.cpp的文件頭加上:
       #include "mmsystem.h"

      并且點(diǎn)擊VC++菜單上的“工程”-“設(shè)置”進(jìn)入Link屬性頁(yè),在L對(duì)象/庫(kù)模塊下輸入:winmm.lib后確定即可.

      (4)添加輸出標(biāo)識(shí)
      在Hook.def的末尾添加

      installhook
      KeyboardProc

      短短的四步,鍵盤(pán)鉤子的制作算是完成了,編譯生成后的DLL文件就可以自由的用別的程序來(lái)調(diào)用了.
      在程序中如何調(diào)用DLL呢?那就簡(jiǎn)單了.再用VC++6.0新建一個(gè)MFC AppWizard(exe)工程,命名為KeySound,點(diǎn)擊"確定"后選擇程序類型為對(duì)話框,直接點(diǎn)擊確定即可.
      在KeySoundDlg.cpp文件中的OnInitDialog()初始化函數(shù)的CDialog::OnInitDialog();下面添加:

      //阻止程序反復(fù)駐留內(nèi)存,也為了防止有兩個(gè)程序同時(shí)讀取DLL而發(fā)生錯(cuò)誤.

      CreateMutex(NULL, FALSE, "KeySound");
      if(GetLastError()==ERROR_ALREADY_EXISTS)
         OnOK();
      
      //讀取DLL
      static HINSTANCE hinstDLL; 
      typedef BOOL (CALLBACK *inshook)(); 
      inshook instkbhook;
      if(hinstDLL=LoadLibrary((LPCTSTR)"Hook.dll"))
      {
          instkbhook=(inshook)GetProcAddress(hinstDLL,"installhook");  
          instkbhook();
      }
      else
      {
          MessageBox("當(dāng)前目錄找不到Hook.dll文件,程序初始化失敗");
          OnOK();
      }

      將編譯生成后的KeySound.exe和Hook.dll放在同一目錄下,定義好聲音文件,運(yùn)行KeySound.exe后打開(kāi)記事本或?qū)懽职?,體驗(yàn)一下系統(tǒng)為您即時(shí)快速地朗讀您按下的每一個(gè)鍵的快感吧^-^

      有一點(diǎn)必須說(shuō)明,標(biāo)準(zhǔn)鍵盤(pán)有101個(gè)鍵,您想讓多少鍵發(fā)聲音,就必須在上面的KeyboardProc動(dòng)作里定義多少個(gè)鍵,常用的10個(gè)數(shù)字鍵和26個(gè)英文字母不會(huì)給您帶來(lái)太大的困難,只要相應(yīng)的''A''對(duì)應(yīng)A鍵,''1''對(duì)應(yīng)1鍵就可以,但如果您希望能讓更多的鍵都有各種特色音樂(lè)的話,很可能會(huì)遇到一些鍵盤(pán)編碼上的麻煩,比如ESC鍵就不能簡(jiǎn)單的用''ESC''來(lái)搞定了,得用VK_ESCAPE,又比如Alt鍵得用VK_MENU來(lái)定義,沒(méi)有個(gè)鍵盤(pán)編碼表的話會(huì)令人相當(dāng)頭疼,這里我介紹一種讓程序來(lái)告訴您鍵盤(pán)按鍵名稱的方法:
      為一個(gè)工程添加PreTranslateMessage映射,添加如下代碼:

      char KeyName[50];
      ZeroMemory(KeyName,50);
      if(pMsg -> message == WM_KEYDOWN)
      { 
         GetKeyNameText(pMsg->lParam,KeyName,50);
         MessageBox(KeyName);
      } 
      那么當(dāng)程序窗口顯示在面前時(shí)按下某個(gè)鍵,就會(huì)彈出一個(gè)消息顯示該鍵的名稱,然后用''''包起來(lái)就可以了,比如逗號(hào)句號(hào),就是'',''和''.'',簡(jiǎn)單吧:)

      到此就全部完成了按鍵發(fā)音程序的編寫(xiě),通過(guò)改變聲音文件的名稱而不用改動(dòng)程序本身就可以達(dá)到更換按鍵聲音的目的了,只是有個(gè)遺憾,聲音文件在硬盤(pán)中的位置不能變更,從C盤(pán)換移動(dòng)D盤(pán)程序就不能播放了,怎么樣才能靈活的讀取聲音文件呢?可以用API函數(shù)GetModuleFileName來(lái)得到程序所在的目錄,具體實(shí)現(xiàn)方法如下:
      (1)在Hook.h的public:下面添加:

      BOOL InitInstance(); //初始化函數(shù)

      (2)在Hook.cpp的#endif下添加定義全局變量的代碼:

      char szBuf[256];
      char *p;
      CString msg;

      (3)在Hook.cpp中適當(dāng)位置添加:

      BOOL CHookApp::InitInstance ()
      { 
         hins=AfxGetInstanceHandle();
         GetModuleFileName(AfxGetInstanceHandle( ),szBuf,sizeof(szBuf));
         p = szBuf;
         while(strchr(p,''\\'')) 
         { 
              p = strchr(p,''\\''); 
              p++; 
         }
         *p = ''\0''; 
         msg=szBuf;
         return TRUE; 
      }

      (4)新建一個(gè)文件夾并命名為Sound;

      (5)改變聲音文件物理位置定義方式
      case ''1'':sndPlaySound(msg+"sound\\1.wav",SND_ASYNC);break; 

      msg是得到程序當(dāng)前所在目錄,加上后面的代碼就是指播放當(dāng)前目錄下的Sound目錄里的1.wav文件,這樣就將聲音文件的絕對(duì)路徑改成了靈活的相對(duì)路徑.您只要把KeySound.exe,Hook.dll和Sound文件夾放在同一個(gè)文件夾下,以后只要搬動(dòng)整個(gè)文件夾就能實(shí)現(xiàn)聲音文件的任意移動(dòng)了。

      調(diào)試時(shí)需要注意:將Hook.dll、Sound目錄放在KeySound.exe的執(zhí)行目錄下。假如編譯鏈接的時(shí)候出現(xiàn)unresolved external symbol __imp__sndPlaySoundA@8 這樣的信息,請(qǐng)?jiān)赑roject Settings中加入Winmm.lib 

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多