在上一篇文章
中,寫了一個sample
,用於隱藏表徵圖,但是有網友提出,能不能在程式介面上顯示當前的托盤表徵圖,這樣更直觀一些。這一點我也曾想到過,也知道奧秘就在TBBUTTON這個結構體的dwData域裡面,可惜這個域的結構在MSDN
中沒有描述。我也曾試著發送TB_GETIMAGELIST訊息擷取image list的控制代碼,然後用CImageList::FromHandle載入到CImageList中,但卻都失敗了。
在csdn
網友的協助下,我弄清了dwData的結構,並據此改進了程式,下面的是改進版啟動並執行畫面。
其實dwData有一個這樣的機構,我們命名為TRAYDATA:
- struct
TRAYDATA
- {
-
HWND
hwnd;
-
UINT
uID;
-
UINT
uCallbackMessage;
-
DWORD
Reserved[2];
-
HICON
hIcon;
//托盤表徵圖的控制代碼
- };
要擷取到這個hIcon,其實很簡單:
- //分配虛擬記憶體
- lngAddress = VirtualAllocEx(hProcess, NULL,
sizeof
(TBBUTTON), MEM_COMMIT, PAGE_READWRITE);
-
- //將hProcess進程內,地址為lngAddress中的內容(大小為sizeof(TBBUTTON))擷取到tb中
- ret = ::ReadProcessMemory(hProcess, LPVOID(
long
(lngAddress)), &tb,
sizeof
(TBBUTTON), 0);
- //將hProcess進程內,地址為tb.dwData中的內容(大小為sizeof(TRAYDATA))擷取到tray中
- ret = ::ReadProcessMemory(hProcess, LPVOID(tb.dwData), &tray,
sizeof
(TRAYDATA), 0);
然後就可以用tray.hIcon索引到這個表徵圖控制代碼了,此外我們還可以用tray.hwnd擷取到它所在進程的執行路徑,最後我們添加一個CListControl控制項,並在OnInitDialog()過程中進行控制項的初始化:
- m_ImageList.Create(16,16,ILC_COLOR24,16,16);
- m_ListCtl.SetImageList(&m_ImageList,LVSIL_SMALL);
- m_ListCtl.SetExtendedStyle(LVS_EX_FULLROWSELECT);
- m_ListCtl.InsertColumn(0,
"表徵圖"
, LVCFMT_LEFT, 50);
- m_ListCtl.InsertColumn(1,
"應用程式路徑"
, LVCFMT_LEFT, 500);
- m_ListCtl.InsertColumn(2,
"提示資訊"
, LVCFMT_LEFT,300);
最後將擷取到的資訊填入這個控制項中:
- lv.iSubItem = 0;
- lv.mask = LVIF_IMAGE;
- lv.iItem = m_ListCtl.GetItemCount();
-
-
if
(GetIconInfo(tray.hIcon,&icon_info) != 0)
- {
- lv.iImage = m_ImageList.Add(tray.hIcon);
- ::ZeroMemory(&icon_info,
sizeof
(ICONINFO));
- }
- m_TifoVec.push_back(tifo);
-
int
index = m_ListCtl.InsertItem(&lv);
- m_ListCtl.SetItemText(index,1,GetFilenameFromPid(dwProcessId));
-
if
(!(tb.fsState&TBSTATE_HIDDEN))
- {
- ret = ::ReadProcessMemory(hProcess,
LPVOID
(tb.iString),&strBuff,1024,0);
- USES_CONVERSION;
- m_ListCtl.SetItemText(index,2,OLE2T((LPOLESTR)(strBuff)));
- }
-
else
- {
- m_ListCtl.SetItemText(index,2,
"[Hidden Icon]"
);
- }
此外,因為我們能得到進程id,所以可以有更多的應用,這裡就不示範了,這個改進版的代碼可以在這裡下載
。