Re[2]: Найти иконку в трее
Здравствуйте, Алексей.
Monday, February 13, 2006, 11:58:18 AM, you wrote:
А> Вобщем я делал так. System Tray это toolbar с кнопками. Все что нужно
А> это получить список этих кнопок. Прям так сходу не смогу сказать как
А> это делается, MSDN нет под рукой. Что то типа GET_BUTTON мессадж
А> должен быть. Могу поискать проект на делфи если интересует. Эту идею в
А> свое время я высмотрел на CodeProject.com. Там проект был на C++
А> написан.
Был бы Вам очень признателен за этот проект. Вообще-то, я нашел пример
на С++ и переделал его на Делфу. Получилось такое:
var
wnd,hpr :HWND;
pid :Cardinal;
n,i :Integer;
bt :PTBBUTTON;
mBt,mRect :Pointer;
r :TRect;
RBytes :DWORD;
p :PChar;
begin
wnd := FindWindowEx(0,0,'Shell_TrayWnd',0);
wnd := FindWindowEx(wnd,0,'TrayNotifyWnd',0);
wnd := FindWindowEx(wnd,0,'SysPager',0);
wnd := FindWindowEx(wnd,0,'ToolbarWindow32',0);
GetWindowThreadProcessId(wnd, pid);
hpr := OpenProcess(PROCESS_VM_OPERATION or PROCESS_VM_READ, False, pid);
mBt := VirtualAllocEx(hpr, nil, SizeOf(TTBButton), MEM_COMMIT or MEM_RESERVE,
PAGE_READWRITE);
mRect := VirtualAllocEx(hpr, nil, SizeOf(TRect), MEM_COMMIT or MEM_RESERVE,
PAGE_READWRITE);
GetMem(p, 255);
lbx.Items.Clear;
n := SendMessage(wnd, TB_BUTTONCOUNT, 0, 0);
for i := 0 to n-1 do
begin
// ZeroMemory(mBt, SizeOf(mBt^));
if BOOL(SendMessage(wnd, TB_GETBUTTON, WParam(i), LParam(Bt))) then
Tag := SendMessage(wnd, TB_GETBUTTONTEXT, Bt.idCommand, LParam(p));
// if BOOL(ReadProcessMemory(hpr, mBt, @bt, SizeOf(TTBButton), RBytes))
then
// Tag := SendMessage(wnd, TB_GETBUTTONTEXT, bt.idCommand, LParam(p[0]));
end;
FreeMem(p, 255);
VirtualFreeEx(hPr, mBt, 0, MEM_RELEASE);
VirtualFreeEx(hPr, mRect, 0, MEM_RELEASE);
// close thread process handle
CloseHandle(hPr);
end;
Я тут в качестве эксперементов "поначеркивал" и поудалял кое-что по
сравнению с оригиналом. Cамое интересное то, что число кнопок в трее
определяет четко, а вот чтобы определить параметры i-ой кнопки... В
принципе, я понимаю, почему так происходит - число-то определяется по
хэндлу бара. А после, этого я начинаю "плавать", поскольку не совсем
понимаю, как добраться до этой i-й кнопки. В частности, у меня большое
удивление вызывает то, что SendMessage(wnd, TB_GETBUTTON, WParam(i),
LParam(Bt)) в Bt возвращает одно и то же для любого i.
В общем, если меня поправите, буду признателен.
Кстати, вот оригинальный текст на С. Но даже при более-менее точном
его переводе на Делфи ничего не вышло.
HWND hWnd; // my window
RECT rcTray; // my icon rect
HWND hTrayToolTip; // tray tooltip
HWND hTrayBalloon; // tray balloon
HWND hTrayToolBar; // handle to tray window
bool SetTrayToolRect(bool LocateHints)
{
// find shell tray window
HWND hShellTray = ::FindWindow("Shell_TrayWnd",NULL);
// find tray notify window
HWND hTrayNotify = ::FindWindowEx(hShellTray, NULL, "TrayNotifyWnd", NULL);
// find tray toolbar
hTrayToolBar = ::FindWindowEx(hTrayNotify, NULL, "ToolbarWindow32", NULL);
// get shell tray thread and process ids
DWORD dTrayProcess, dTrayThread;
dTrayThread = ::GetWindowThreadProcessId(hTrayToolBar, &dTrayProcess);
// locate hints
if (LocateHints)
{
// find tray balloon and tooltip
hTrayBalloon = NULL;
hTrayToolTip = NULL;
// find window
HWND hBalloon = ::FindWindowEx(NULL, NULL, TOOLTIPS_CLASS, NULL);
while (hBalloon)
{
DWORD dProcess, dThread;
dThread = ::GetWindowThreadProcessId(hBalloon, &dProcess);
if (dThread == dTrayThread && dProcess == dTrayProcess)
{
// balloon style
if (::GetWindowLong(hBalloon, GWL_STYLE) & TTS_BALLOON)
{
hTrayBalloon = hBalloon;
if (hTrayToolTip) break;
}
// tooltip
if ((::GetWindowLong(hBalloon, GWL_STYLE) & TTS_NOPREFIX) == 0)
{
hTrayToolTip = hBalloon;
if (hTrayBalloon) break;
}
}
// get next window
hBalloon = ::FindWindowEx(NULL, hBalloon, TOOLTIPS_CLASS, NULL);
}
}
// open tray process
HANDLE hTrayProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dTrayProcess);
// allocate memory in tray process
// button info
void* mButton = ::VirtualAllocEx(hTrayProcess, NULL, sizeof(TBBUTTON),
MEM_COMMIT, PAGE_READWRITE);
// rect
void* mRect = ::VirtualAllocEx(hTrayProcess, NULL, sizeof(RECT),
MEM_COMMIT, PAGE_READWRITE);
// handle to window receiving tray messages
void* mWnd = ::VirtualAllocEx(hTrayProcess, NULL, sizeof(HWND),
MEM_COMMIT, PAGE_READWRITE);
// look for the icon
bool Found = false;
// get buttons count
int nButtons = ::SendMessage(hTrayToolBar, TB_BUTTONCOUNT, 0, 0);
for (int i=0; i<nButtons; i++)
{
// reset button
TBBUTTON Button;
::ZeroMemory(&Button, sizeof(TBBUTTON));
DWORD ReadBytes = 0;
// get button
::SendMessage(hTrayToolBar, TB_GETBUTTON, i, LPARAM(mButton));
// transfer to local address space
::ReadProcessMemory(hTrayProcess, mButton, &Button, sizeof(TBBUTTON), &ReadBytes);
// get icon owner window handle - this is the trick!!! ;)
HWND hCompareWnd = NULL;
// transfer to local address space
::ReadProcessMemory(hTrayProcess, (void*)Button.dwData, &hCompareWnd, sizeof(HWND),
&ReadBytes);
// compare handles
if (hCompareWnd == hOwner)
{
// found
::ZeroMemory(&rcTrayIcon, sizeof(RECT));
// get icon rect
::SendMessage(hTrayToolBar, TB_GETRECT, Button.idCommand, LPARAM(mRect));
// convert to local space
::ReadProcessMemory(hTrayProcess, mRect, &rcTrayIcon, sizeof(RECT), &ReadBytes);
// end searching
Found = true;
break;
}
}
// free memory in tray process
::VirtualFreeEx(hTrayProcess, mButton, 0, MEM_RELEASE);
::VirtualFreeEx(hTrayProcess, mRect, 0, MEM_RELEASE);
::VirtualFreeEx(hTrayProcess, mWnd, 0, MEM_RELEASE);
// close thread process handle
::CloseHandle(hTrayProcess);
// check result
if (!Found)
{
// reset
::ZeroMemory(&rcTrayIcon, sizeof(RECT));
return false;
}
// convert to screen
::ClientToScreen(hTrayToolBar, (POINT*)(&(rcTrayIcon.left)));
::ClientToScreen(hTrayToolBar, (POINT*)(&(rcTrayIcon.right)));
// successful return
return true;
}