前一陣子換了一個好看的桌面,但是圖標太多擋住了很不高興,在桌面點右鍵,隱藏桌面圖片很麻煩,於是想做一個小軟件一鍵隱藏、顯示桌面圖標,好讓我欣賞壁紙。
鑑於這陣子學習C語言,就用C++寫一個程序。暫定爲雙擊鼠標右鍵,隱藏桌面圖標。
查詢得知,需要關鍵的技術爲HOOK。於是開始動工。
首先,要解決的是如何執行隱藏操作。
鑑於之前做過一個類似的C#程序,我先嚐試了模擬按鍵:找到桌面的句柄後,依次按下,鼠標右鍵(或菜單鍵)、查看(快捷鍵V)、顯示桌面圖標(快捷鍵D)。經過百般嘗試,最終得出結論,我對桌面發送右鍵可以執行,緊接着的模擬鍵盤都不成功,按鍵應該對應菜單項的句柄才能發送。我暫時放棄了這個方法。
然後經過SPY++捕捉系統消息,查閱msdn得出了一個消息ShowWindow(hwnd,SW_HIDE); 這個消息可以隱藏桌面,測試通過。
然後,解決響應鼠標雙擊。
寫了一個簡單的HOOK程序,使用MH_MOUSE_LL全局鼠標鉤子,無需DLL注入。測試單擊左鍵右鍵,配合ShowWindow這個消息,已經可以顯示隱藏桌面圖標了。但是對於雙擊鼠標,程序始終沒有響應。查閱資料得知,MH_MOUSE_LL方法雖然省事,但是他能捕獲到的鼠標消息只有,單擊,移動,並沒有雙擊這個消息。
我還走了一段彎路,以爲console程序就不支持鼠標雙擊事件,還寫了一個MFC窗口,才發現,支持的雙擊僅限於在窗口本身操作,並是不我想要的HOOK全局雙擊。
既然沒有雙擊,解決方案就兩種,一是自己寫個計時器,來監控兩次單擊的時間間隔;另一種是改用MH_GETMESSAGE DLL注入全局攔截雙擊事件。這裏我選用第一種,最終完成,代碼如下。
#include "stdafx.h"
#include <windows.h>
DWORD lastTime;
BOOL lastIsRight=FALSE;
BOOL isHiden=FALSE; //定義爲全局變量,每次點擊保證重新載入值
LRESULT CALLBACK LowLevelMouseProc(
int nCode,
WPARAM wParam,
LPARAM lParam
)
{
typedef void (WINAPI *PSWITCHTOTHISWINDOW) (HWND,BOOL);
PSWITCHTOTHISWINDOW SwitchToThisWindow;
HMODULE hUser32=GetModuleHandle(_T("user32"));
//載入窗口前置函數
SwitchToThisWindow=(PSWITCHTOTHISWINDOW)GetProcAddress(hUser32,"SwitchToThisWindow");
HWND hwnd =FindWindow(_T("Progman"),NULL);
hwnd = FindWindowEx(hwnd, NULL, _T("SHELLDLL_DefView"), NULL);
hwnd = FindWindowEx(hwnd, NULL, _T("SysListView32"), NULL);
//桌面句柄查找
if(hwnd!=NULL){
if (nCode>=0)
{
if(wParam==WM_RBUTTONUP)
{
if(!lastIsRight)
{
lastTime=::GetTickCount();
lastIsRight=TRUE;
}
else
{
DWORD nowTime=::GetTickCount();
if(nowTime-lastTime<350)//時間間隔爲350ms
{
if(!isHiden) {ShowWindow(hwnd,SW_HIDE);isHiden=TRUE;}
else {ShowWindow(hwnd,SW_SHOW);isHiden=FALSE;}
lastIsRight=FALSE;
}
else
lastTime=nowTime;
}
}
}
}
return CallNextHookEx(0,nCode,wParam,lParam);
}
int _tmain(int argc, _TCHAR* argv[])
{
MSG msg;
SetWindowsHookExW(WH_MOUSE_LL,LowLevelMouseProc,GetModuleHandleW(0),0);
while(GetMessageW(&msg,0,0,0))DispatchMessageW(&msg);
return 0;
}