利用鉤子函數來注入DLL的一個具體應用:點擊案頭不同表徵圖,播放相應音符

來源:互聯網
上載者:User

最近看核心編程,看到DLL注入這一章,有一個Desktop Item Positon Saver(DIPS)的例子,這個例子是使用視窗掛鈎來將一個DLL注入到Explorer.exe的地址空間中,來儲存和恢複表徵圖位置。
於是便想根據這個例子自己改造一下,正好前段時間看到在 Google 的首頁上,Google為了紀念電吉他之父萊斯·保羅 96 周年誕辰,特意做了一個很有意思的Doodle,這個 Google電吉他Logo可以讓使用者在其上面彈奏吉他,於是便想利用案頭表徵圖來編一個類似的程式,點擊不同的表徵圖,發出不同的吉他音色的音符。
下面把編程的大概思路說一下:
首先就是找到案頭ListView控制項的視窗控制代碼,剛開始在這裡就遇到了問題。
核心編程這本書上講到Windows外殼有一個類別為ProgMan的視窗,這個ProgMan視窗有且只有一個類別為SHELLDLL_DefView的子視窗。這個子視窗同樣有且只有一個子視窗,子視窗的類別為SysListView32,這個SysListView32視窗就是案頭的ListView控制項視窗。
於是我便利用了它的代碼:
HWND hWndLV =GetFirstChild(GetFirstChild(
      FindWindow(TEXT("ProgMan"), NULL)));
但發現運行不正確,於是便使用spy++查看,發現我的SysListView32視窗是位於類為WorkerW的視窗下。難道這是win7系統更改的?我也不清楚。因此,如果大家下載下來我的原始碼後,如果運行不成功,最好用spy++查看一下視窗資訊,看一看SysListView32控制項到底是誰的子視窗,如果是ProgMan的子視窗,那麼大家需要把MouseHookApp.cpp檔案中的
HWND hWndLV;
   EnumWindows(EnumWindowsProc,(LPARAM)&hWndLV);

EnumWindowsProc函數注釋掉,
取消HWND hWndLV =GetFirstChild(GetFirstChild(
      FindWindow(TEXT("ProgMan"), NULL)));這一代碼的注釋。
我發現類名為WorkerW的視窗不是唯一的,因此不能使用FindWindows了,改用了EnumWindows函數。
HWND hWndLV;
   EnumWindows(EnumWindowsProc,(LPARAM)&hWndLV);

其中的EnumWindowsProc函數實現如下:

代碼:BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam){<br /> if(hwnd)<br /> {<br /> TCHAR classname[128];<br /> GetClassName(hwnd, classname, 128);<br /> if(!_tcscmp(classname, _T("WorkerW") ) )<br /> {<br /> HWND &hWndLV = *(HWND *)lParam;<br /> TCHAR childClassName[128];<br /> HWND hChildWnd = GetWindow(hwnd, GW_CHILD);<br /> while(hChildWnd)<br /> {<br /> GetClassName(hChildWnd, childClassName, 128);<br /> if(!_tcscmp(childClassName, _T("SHELLDLL_DefView")))<br /> hWndLV = GetFirstChild(hChildWnd);<br /> chASSERT(IsWindow(hWndLV));<br /> return false;<br /> }<br /> }<br /> }</p><p> return true;<br />}<br />好了,現在得到案頭ListView控制項的控制代碼了,下面就需要編寫注入到Explorer.exe中的DLL檔案了。遇到的問題主要有兩個:
第一個就是註冊了滑鼠訊息的鉤子函數後,如何判斷滑鼠點擊的是表徵圖的哪一項,經過各方面尋找資料並實驗後發現以下一種可行方法:
 

代碼:LVITEM lvi;<br /> LVHITTESTINFO lvh={0};<br /> int iIndexItem;<br /> long lx = pMouseHook->pt.x;//pMouseHook是指向MOUSEHOOKSTRUCT結構體的指標<br /> long ly = pMouseHook->pt.y;<br /> lvh.pt.x = lx;<br /> lvh.pt.y = ly;<br /> ScreenToClient(pMouseHook->hwnd, &(lvh.pt));<br /> ListView_HitTest(pMouseHook->hwnd, &lvh);<br /> iIndexItem = lvh.iItem;<br /> if(iIndexItem !=-1)<br /> {<br /> ZeroMemory(&lvi, sizeof(lvi));<br /> lvi.mask = LVIF_TEXT;<br /> lvi.iItem = iIndexItem;<br /> lvi.pszText = szBuff;<br /> lvi.cchTextMax = _countof(szBuff);</p><p> if(ListView_GetItem(pMouseHook->hwnd, &lvi))<br /> {<br /> wsprintf(szDebug, TEXT("item text = '%s'"), szBuff);<br /> OutputDebugString (szDebug);<br /> }<br />遇到的第二個問題主要是音符播放問題,由於以前沒接觸過這方面的知識,所以剛開始沒有什麼頭緒,後來發現應該使用MIDI方面的知識。
主要用到的函數有midiOutOpen和midiOutShortMsg函數,具體該函數的用法,大家可以參考一下MSDN。
函數GetSelectedItem的主要代碼如下:代碼:LVHITTESTINFO lvh={0};<br /> int iIndexItem;<br /> int keyNo, iOctave, iNote ;<br /> long lx = lmhs->pt.x;<br /> long ly = lmhs->pt.y;<br /> lvh.pt.x = lx;<br /> lvh.pt.y = ly;</p><p> ScreenToClient(lmhs->hwnd, &(lvh.pt));<br /> ListView_HitTest(lmhs->hwnd, &lvh);<br /> iIndexItem = lvh.iItem;<br /> if(iIndexItem !=-1)<br /> {<br /> POINT ItemPt;<br /> ListView_GetItemPosition(lmhs->hwnd, iIndexItem, &ItemPt);<br /> /*wsprintf(szDebug, TEXT("item coordinate = '%d, %d'"), ItemPt.x, ItemPt.y);<br /> OutputDebugString (szDebug); */<br /> int lineNo = ItemPt.x/75;<br /> int colNo = ItemPt.y/86;<br /> keyNo = lineNo*10+colNo;<br /> if (keyNo >= NUMSCANS) // No scan codes over 53<br /> return ;</p><p> if ((iOctave = notes[keyNo].iOctave) == -1) // Non-music key<br /> return ;<br /> iNote = notes[keyNo].iNote ;<br /> if(keyNo <30)<br /> MidiNoteOn (hMidiOut, 0, iOctave, iNote, iVelocity) ; // Note on<br /> else<br /> {<br /> MidiSetPatch (hMidiOut, 9, 0) ;<br /> MidiNoteOn (hMidiOut, 9, iOctave, iNote, iVelocity) ; // Note on<br /> }<br />主要的部分就是這些,關於如何安裝鉤子函數,截取滑鼠訊息等等,這裡我就不再贅述了,網上有很多具體資料,也可以查看我的原始碼。
大家在運行原始碼是,還有一個問題,就是螢幕解析度問題,因為表徵圖在案頭上的位置與間隔隨著螢幕解析度的不同會有差別,而我程式中判斷表徵圖位置的代碼,
int lineNo = ItemPt.x/75;
int colNo = ItemPt.y/86;
其中的75和86分別是我自己螢幕解析度的情況下(1440x900)一個表徵圖與上標和左右表徵圖之間上下和左右的距離。我這裡為了省事,就直接寫死了,沒有對其進行程式上的判段,嘿嘿,今後為了通用性,肯定還是會改進的,現在先湊合著用吧。
如果大家想知道自己螢幕解析度下的表徵圖之間的距離,可以把上述GetSelectedItem函數代碼中的
/*wsprintf(szDebug, TEXT("item coordinate = '%d, %d'"), ItemPt.x, ItemPt.y);
    OutputDebugString (szDebug); */
注釋取消掉,然後運行程式,點擊表徵圖,使用debugview軟體查看輸出地座標資訊,自己計算出相鄰表徵圖的距離,把75 和86替換掉即可。

程式運行後點擊MusicHook按鈕就可以了,這是點擊案頭表徵圖就可以發出音符聲音了。取消hook點擊UnHook按鈕。
大致情況就是這樣。最後把收集到的一些吉他的曲譜附上供大家參考玩耍,嘿嘿。
小星星:1155665 4433221 5544332 5544332 1155665 4433221;
賣報歌:555 555 35653 235 53532 132 332 612 665 365 53235 5323 5323 61231
月亮之上:3686 3675 53686565326553 3686 89865 36865326656
糰子大家族:325 56 67 52 325 565 325 56 67 52 325 565 8753 5635 235 8753 5635 235 251
兩隻老虎: 1231|1231|345|345|565431|565431|151|151||  (最愛,哈哈)
童年:35553 6676 66588886865 355536676 66658888668 9~
上海灘:356666,352222,356865132 以上是轉載自本人特別喜歡的看雪論壇中的文章:這裡特意給出連結:http://bbs.pediy.com/showthread.php?t=136144至於原始碼可以去原帖論壇下載,或者直接向本人索要,學習交流。E-MAIL:1071545795@qq.com

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.