witam! czy jest możliwość za pomocą winapi (lub innym sposobem) pobrać tekst który pojawia się kiedy najedziemy na jakąś ikonkę w trayu (ten w dymku)? Jeśli tak to jaka funkcja? z góry dzięki!
- Rejestracja:prawie 20 lat
- Ostatnio:21 minut
- Lokalizacja:Gorlice

- Rejestracja:prawie 17 lat
- Ostatnio:około 3 lata
- Lokalizacja:Szczecin
- Postów:4191
Z tego co widze, najwązniejszy kod dla ciebie jest w pliku ShellTrayInfoView.cpp
i zaczyna się od tekstu void CShellTrayInfoView::ListTrayIcons
. Sam próbowałem znalezione w google kody w Delphi z użyciem komunikatu TB_GETBUTTON
przerobić i uzupełnić aby odczytywały też tak zwany ToolTip, ale nie bardzo mi to wyszło.
- Rejestracja:prawie 20 lat
- Ostatnio:21 minut
- Lokalizacja:Gorlice
Wersja dla Delphi (ale odpowiedzialne za pobranie info funkcje to WinApi więc można sobie przetłumaczyć na inny język) pobierania info o ikonach w trayu może komuś się przyda:
Na formie ListView, ImageList i Button
ListView ma 3 kolumny i przypisany jako SmallImages ImageList
//do uses CommCtrl, PsApi
//zwraca sciezkę i nazwe proceu parametr to PID
function GetFilenameFromPid(PID: Cardinal): string;
var
hProcess: Cardinal;
buff: array[0..MAX_PATH - 1] of Char;
begin
result:= '';
hProcess:= OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, PID);
if (hProcess > 0) then
begin
if GetModuleFileNameEx(hProcess, 0, buff, MAX_PATH) > 0 then
result:= buff;
CloseHandle(hProcess);
end;
end;
//zwraca uchwyt toolbara traya
function FindTrayToolbarWindow: Cardinal;
const
WND_CLASS_ARRAY: array [0..3] of string =
('Shell_TrayWnd', 'TrayNotifyWnd', 'SysPager', 'ToolbarWindow32');
var
i: Integer;
begin
i:= Low(WND_CLASS_ARRAY);
result:= FindWindow(PAnsiChar(WND_CLASS_ARRAY[i]), nil);
Inc(i);
while ((result > 0) and (i <= High(WND_CLASS_ARRAY))) do
begin
result:= FindWindowEx(result, 0, PAnsiChar(WND_CLASS_ARRAY[i]), nil);
Inc(i);
end;
end;
procedure TForm1.btnLoadTrayIconsInfoClick(Sender: TObject);
type
_EXTRADATA = packed record
hWnd: THandle;
uID: UINT;
uCallbackMessage: UINT;
Reserved: array [0..1] of DWORD;
hIcon: HICON;
end;
var
pTrayBtnData: Pointer;
hTray, hProcessExplorer: Cardinal;
dwExplorerProcessID, dwBytesRead, dwTrayButtonCount: Cardinal;
ButtonData: _TBBUTTON;
ExtraData: _EXTRADATA;
ToolTip: array [0..1024] of WideChar;
pIconInfo: _ICONINFO;
i: Integer;
dwInfoProcessID: Cardinal;
sInfoProcessName: string;
sInfoToolTip: string;
hInfoIcon: Cardinal;
li: TListItem;
ico: TIcon;
begin
ImageList1.Clear;
ListView1.Clear;
hTray:= FindTrayToolbarWindow;
if hTray = 0 then exit;
if (GetWindowThreadProcessId(hTray, dwExplorerProcessID) = 0) then exit;
hProcessExplorer:= OpenProcess(PROCESS_ALL_ACCESS, False, dwExplorerProcessID);
if (hProcessExplorer = 0) then exit;
pTrayBtnData:= VirtualAllocEx(hProcessExplorer, nil, SizeOf(_TBBUTTON),
MEM_COMMIT, PAGE_READWRITE);
if (Assigned(pTrayBtnData)) then
begin
dwTrayButtonCount:= SendMessage(hTray, TB_BUTTONCOUNT, 0, 0);
for i:= 0 to dwTrayButtonCount - 1 do
begin
SendMessage(hTray, TB_GETBUTTON, i, Longint(pTrayBtnData));
if ReadProcessMemory(hProcessExplorer, pTrayBtnData, @ButtonData,
SizeOf(_TBBUTTON), dwBytesRead) and (dwBytesRead = SizeOf(_TBBUTTON)) then
begin
sInfoProcessName:= '';
hInfoIcon:= 0;
if ReadProcessMemory(hProcessExplorer, Pointer(ButtonData.dwData),
@ExtraData, SizeOf(_EXTRADATA), dwBytesRead) and
(dwBytesRead = SizeOf(_EXTRADATA)) then
begin
GetWindowThreadProcessId(ExtraData.hWnd, dwInfoProcessID);
sInfoProcessName:= GetFilenameFromPid(dwInfoProcessID);
hInfoIcon:= ExtraData.hIcon;
end;
sInfoToolTip:= '';
if ReadProcessMemory(hProcessExplorer, Pointer(ButtonData.iString),
@ToolTip, 1024, dwBytesRead) and (dwBytesRead = 1024) then
sInfoToolTip:= WideCharToString(ToolTip);
li:= ListView1.Items.Add;
li.SubItems.Add(sInfoToolTip);
li.SubItems.Add(sInfoProcessName);
li.ImageIndex:= -1;
if GetIconInfo(hInfoIcon, pIconInfo) then
begin
ico:= TIcon.Create;
try
ico.Handle:= hInfoIcon;
li.ImageIndex:= ImageList1.AddIcon(ico);
finally
ico.Free;
end;
end;
end;
end;
VirtualFreeEx(hProcessExplorer, pTrayBtnData, 0, MEM_RELEASE);
end;
CloseHandle(hProcessExplorer);
end;

- Rejestracja:prawie 17 lat
- Ostatnio:około 3 lata
- Lokalizacja:Szczecin
- Postów:4191
@kAzek: rozumiem, że kod działa u Ciebie prawidłowo? Bo u mnie efekt jego działania jest widoczny na obrazie poniżej. Za pewne "winny" jest tutaj 64 bitowy system. Jednak kody znalezione na google dla wersji 64 bitowej, wprawdzie na podobnej zasadzie, ale tylko dla odświeżenia obszaru Tray, też nie pomogły mi sklecić nic samodzielnie. Po prostu if
po hInfoIcon := 0;
nie wykonuje się, a poza tym nawet jeżeli by z niego zrezygnować to ExtraData.hWnd
pokazuje zawsze ten sam uchwyt. Masz może pomysł jak zmusić do prawidłowego działania Twój kod na systemie Windows 7 Ultimate 64 bit? Bo moze trzeba było by jakoś "scalić" kod z http://www.delmadang.com/community/bbs_print.asp?bbsNo=3&bbsCat=0&indx=428067 który działa ok jeśli chodzi o odświeżanie i przetumaczyć kod z http://www.haogongju.net/art/1282689 na Delphi, który uwzględnia bitowośc systemu.
- kazek_code_test.jpg (27 KB) - ściągnięć: 143

- Rejestracja:prawie 17 lat
- Ostatnio:około 3 lata
- Lokalizacja:Szczecin
- Postów:4191
@kAzek: próbowałem tłumaczyć kod z: http://www.haogongju.net/art/1282689 - stamtąd można zobaczyć różnicę w ustawianiu offsetu. tyle co potrafiłem to przetłumaczyłem na Delphi, ale chyba nie do konca prawidłowo. Próbując zapisać albo wyświetlić zmienną buff
otrzymuje jakieś znaczki ASCII. Może spojrzysz - kod i exek w załączniku. Natomiast, tak jak pisałem kod z tej strony jeżeli chodzi o odświeżanie działa ok na 64 bitach, tylko nie umiem go zaadaptować do odczytania informacji takich jak ToolTip oraz ewentualnie ikonka danego procesu: http://www.delmadang.com/community/bbs_print.asp?bbsNo=3&bbsCat=0&indx=428067 - jak uda się Tobie coś wykombinować i bedzie to uniwersalny kod dla 32 bitów oraz 64 bitów to proszę daj przykład. Do sprawdzania bitowości systemu najprościej będzie chyba wykorzystać poniższą funkcję, która kompiluje się oczywiście również pod starszymi wersjami Delphi, jak siódemka.
function IsWow64 : boolean;
type
TIsWow64Process = function(hProcess : THANDLE; Wow64Process : PBOOL) : BOOL; stdcall;
var
IsWow64Process : TIsWow64Process;
begin
IsWow64Process := GetProcAddress(GetModuleHandle('kernel32'), 'IsWow64Process');
if Assigned(IsWow64Process) then
begin
IsWow64Process(GetCurrentProcess, @Result);
end;
end;
- tray_test.rar (9 KB) - ściągnięć: 101

- Rejestracja:prawie 20 lat
- Ostatnio:21 minut
- Lokalizacja:Gorlice
@olesio sprawdź nową wersję kodu jest zgodna z nowymi wersjami Delphi, teoretycznie powinna działać pod 64bit ale nie sprawdziłem bo nie mam jak. Jeżeli nadal nie działa to myślę że pod 64 _EXTRADATA też trzeba inaczej zdefiniować :/ Jak coś to napisz co się dzieje tym razem.
//do uses CommCtrl, PsApi
//zwraca sciezkę i nazwe proceu parametr to PID
function GetFilenameFromPid(PID: Cardinal): string;
var
hProcess: Cardinal;
buff: array[0..MAX_PATH - 1] of Char;
begin
result:= '';
hProcess:= OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, PID);
if (hProcess > 0) then
begin
if GetModuleFileNameEx(hProcess, 0, buff, MAX_PATH) > 0 then
result:= buff;
CloseHandle(hProcess);
end;
end;
//zwraca uchwyt toolbara traya
function FindTrayToolbarWindow: Cardinal;
const
{$IFDEF UNICODE}
WND_CLASS_ARRAY: array [0..3] of PWideChar =
('Shell_TrayWnd', 'TrayNotifyWnd', 'SysPager', 'ToolbarWindow32');
{$ELSE}
WND_CLASS_ARRAY: array [0..3] of PAnsiChar =
('Shell_TrayWnd', 'TrayNotifyWnd', 'SysPager', 'ToolbarWindow32');
{$ENDIF}
var
i: Integer;
begin
i:= Low(WND_CLASS_ARRAY);
result:= FindWindow(WND_CLASS_ARRAY[i], nil);
Inc(i);
while ((result > 0) and (i <= High(WND_CLASS_ARRAY))) do
begin
result:= FindWindowEx(result, 0, WND_CLASS_ARRAY[i], nil);
Inc(i);
end;
end;
function IsWow64: Boolean;
type //tak to musi byc bo inaczej sie wyklada w nowych Delphi
TIsWow64Process = function(hProcess : THANDLE; var Wow64Process: BOOL): BOOL; stdcall;
var
IsWow64: BOOL;
IsWow64Process: TIsWow64Process;
begin
result:= False;
@IsWow64Process := GetProcAddress(GetModuleHandle('kernel32'), 'IsWow64Process');
if Assigned(IsWow64Process) then
begin
IsWow64Process(GetCurrentProcess, IsWow64);
result:= IsWow64;
end;
end;
procedure TForm1.btnLoadTrayIconsInfoClick(Sender: TObject);
type
{$IFNDEF _TBBUTTON}
_TBBUTTON = packed record
iBitmap: Integer;
idCommand: Integer;
fsState: Byte;
fsStyle: Byte;
bReserved: array[1..2] of Byte;
dwData: Longint;
iString: Integer;
end;
{$ENDIF}
{$IFNDEF _TBBUTTON64}
_TBBUTTON64 = packed record
iBitmap: Integer;
idCommand: Integer;
fsState: Byte;
fsStyle: Byte;
iReserved: Integer;
bReserved2: array[1..2] of Byte;
dwData: Longint;
iString: Integer;
end;
{$ENDIF}
_EXTRADATA = packed record
hWnd: THandle;
uID: UINT;
uCallbackMessage: UINT;
Reserved: array [0..1] of DWORD;
hIcon: HICON;
end;
const
{$IFNDEF TB_GETBUTTON}
TB_GETBUTTON = WM_USER + 23;
{$ENDIF}
{$IFNDEF TB_BUTTONCOUNT}
TB_BUTTONCOUNT = WM_USER + 24;
{$ENDIF}
var
pTrayBtnData: Pointer;
dwTrayBtnDataSzie: Cardinal;
pButtonData: Pointer;
hTray, hProcessExplorer: Cardinal;
dwExplorerProcessID, dwTrayButtonCount: Cardinal;
{nie wiem dokladnie od jakiej wersji musi byc NativeUInt zakladam w ciemno że od XE jak nie chce sie kompilowac to trzeba zmienic}
{$IF CompilerVersion >= 22}
dwBytesRead: NativeUInt;
{$ELSE}
dwBytesRead: Cardinal;
{$IFEND}
ExtraData: _EXTRADATA;
ToolTip: array [0..1024] of WideChar;
pIconInfo: _ICONINFO;
i: Integer;
dwInfoProcessID: Cardinal;
sInfoProcessName: string;
sInfoToolTip: string;
hInfoIcon: Cardinal;
li: TListItem;
ico: TIcon;
nDataOffset: Integer;
nStrOffset: Integer;
bIs64bit: Boolean;
begin
{$IFNDEF WIN64} //czy 64bit wersja aplikacji
bIs64bit:= IsWow64;
{$ELSE} //no bez jaj pod Mac OS to i tak nie pojdzie wiec nie ma co sie p...c
bIs64bit:= True;
{$ENDIF}
if bIs64bit then
dwTrayBtnDataSzie:= SizeOf(_TBBUTTON64)
else
dwTrayBtnDataSzie:= SizeOf(_TBBUTTON);
ImageList1.Clear;
ListView1.Clear;
hTray:= FindTrayToolbarWindow;
if hTray = 0 then exit;
if (GetWindowThreadProcessId(hTray, dwExplorerProcessID) = 0) then exit;
hProcessExplorer:= OpenProcess(PROCESS_ALL_ACCESS, False, dwExplorerProcessID);
if (hProcessExplorer = 0) then exit;
pTrayBtnData:= VirtualAllocEx(hProcessExplorer, nil, dwTrayBtnDataSzie,
MEM_COMMIT, PAGE_READWRITE);
if (Assigned(pTrayBtnData)) then
begin
pButtonData:= AllocMem(dwTrayBtnDataSzie);
dwTrayButtonCount:= SendMessage(hTray, TB_BUTTONCOUNT, 0, 0);
for i:= 0 to dwTrayButtonCount - 1 do
begin
SendMessage(hTray, TB_GETBUTTON, i, Longint(pTrayBtnData));
if ReadProcessMemory(hProcessExplorer, pTrayBtnData, pButtonData,
dwTrayBtnDataSzie, dwBytesRead) and (dwBytesRead = dwTrayBtnDataSzie) then
begin
if bIs64bit then
begin
nDataOffset:= _TBBUTTON64(pButtonData^).dwData;
nStrOffset:= _TBBUTTON64(pButtonData^).iString;
end
else
begin
nDataOffset:= _TBBUTTON(pButtonData^).dwData;
nStrOffset:= _TBBUTTON(pButtonData^).iString;
end;
dwInfoProcessID:= 0;
sInfoProcessName:= '';
hInfoIcon:= 0;
if ReadProcessMemory(hProcessExplorer, Pointer(nDataOffset),
@ExtraData, SizeOf(_EXTRADATA), dwBytesRead) and
(dwBytesRead = SizeOf(_EXTRADATA)) then
begin
GetWindowThreadProcessId(ExtraData.hWnd, dwInfoProcessID);
sInfoProcessName:= GetFilenameFromPid(dwInfoProcessID);
hInfoIcon:= ExtraData.hIcon;
end;
sInfoToolTip:= '';
if ReadProcessMemory(hProcessExplorer, Pointer(nStrOffset),
@ToolTip, 1024, dwBytesRead) and (dwBytesRead = 1024) then
sInfoToolTip:= WideCharToString(ToolTip);
li:= ListView1.Items.Add;
li.SubItems.Add(sInfoToolTip);
li.SubItems.Add(sInfoProcessName);
li.ImageIndex:= -1;
if GetIconInfo(hInfoIcon, pIconInfo) then
begin
ico:= TIcon.Create;
try
ico.Handle:= hInfoIcon;
li.ImageIndex:= ImageList1.AddIcon(ico);
finally
ico.Free;
end;
end;
end;
end;
FreeMem(pButtonData);
VirtualFreeEx(hProcessExplorer, pTrayBtnData, 0, MEM_RELEASE);
end;
CloseHandle(hProcessExplorer);
end;

- Rejestracja:prawie 17 lat
- Ostatnio:około 3 lata
- Lokalizacja:Szczecin
- Postów:4191
Dziękuję za poświęcenie czasu @kAzek. Ale niestety, w przypadku dwóch procesów pokazują się tylko ich prawidłowe ścieżki (akurat mialem uruchomiony WinAPI i mój program, który globalnym hookiem wykrywa i przebindowuje działanie jednego z klawiszy na klawiaturze). Nadal jednek brak ikonek oraz ToolTipów. A @Azarien: jaką funkcję do tego proponujesz i czy masz może pomysł jak pod Delphi rozwiązać problem poruszony w wątku dla 64 `itowego systemu. Może jednak kod z http://www.haogongju.net/art/1282689 dobrze przetłumaczony na Delphi by zadziałał jak trzeba?
- Rejestracja:prawie 20 lat
- Ostatnio:21 minut
- Lokalizacja:Gorlice
@olesio nie ma sensu tłumaczyć tamtego kodu bo to na jedno wychodzi :/
Na razie błąd to deklaracja _TBBUTTON64 zaraz wyjaśnię o co chodzi:
Według kodu ze strony którą podałeś tam jest:
int nDataOffset = sizeof(TBBUTTON) - sizeof(INT_PTR) - sizeof(DWORD_PTR); //12
int nStrOffset = 18;
if ( IsWow64() ){
//to sie zgadza bo dochodza 4 bajty przed _TBBUTTON64.dwData
nDataOffset+=4;
//a to z dupy wziete bo size of Integer = 4, sizeof longint = 4 sizeof UInt64 = 8 to
//do cholery jakiego typu jest _TBBUTTON64.nDataOffset jak chcą aby zajmowal 6 bajtow
nStrOffset+=6;
}
Więc można spróbować deklarować tak:
{$IFNDEF _TBBUTTON64}
_TBBUTTON64 = packed record
iBitmap: Integer;
idCommand: Integer;
fsState: Byte;
fsStyle: Byte;
bReserved: array[1..6] of Byte;
dwData: Longint;
bReserved: array[1..2] of Byte; //tu dodamy te 2 'zgubione' bajty
iString: Integer;
end;
{$ENDIF}
i wtedy teoretycznie powinno działać.
Ale na msdn znalazłem:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms680553%28v=vs.85%29.aspx
i tam:
typedef struct
{
INT iBitmap;
INT idCommand;
BYTE fsState;
BYTE fsStyle;
BYTE bReserved[6];
UINT64 dwData;
UINT64 iString;
} TBBUTTON64;
a więc TBBUTTON64.dwData i TBBUTTON64.iString są typu UINT64 a ten zajmuje 8 bajtów więc jestem głupi można spróbować zadeklarować tak:
{$IFNDEF _TBBUTTON64}
_TBBUTTON64 = packed record
iBitmap: Integer;
idCommand: Integer;
fsState: Byte;
fsStyle: Byte;
bReserved: array[1..6] of Byte;
dwData: UINT64;
iString: UINT64;
end;
{$ENDIF}
tyle że w kodzie jest rzutowanie na Pointer i znowu do d**y ale spróbuj obie wersje.
PS: Brak ikony moze być z kolei błędem w deklaracji _EXTRADATA (też moze sie różnić na 64 bit) ale to na razie niw ważne trzeba ToolTip obczaić pierwsze a nie w 2 miejscach grzebać jednocześnie

- Rejestracja:prawie 20 lat
- Ostatnio:21 minut
- Lokalizacja:Gorlice
Chyba jednak w pierwszej wersji (w tej co podałem cały kod nowej wersij) deklaracja _TBBUTTON64 jest ok tylko spróbuj zamiast tamtego _EXTRADATA wszędzie (do testu na razie na sztywno) użyć _EXTRADATA64 jak i stopniowo zwiększaj wielkosć tablicy Reserved2 (myślę że nie więcej niż do 16) jak będzie będzie ok to powinna być ikonka:
_EXTRADATA64 = packed record
hWnd: THandle;
uID: UINT;
uCallbackMessage: UINT;
Reserved: array [1..2] of DWORD;
Reserved2: array[1..n] of Byte;
hIcon: HICON;
end;
Co do ToolTip to sprawa taka że nie wiem ReadProcessMemory odczytuje?
Moze tam nie ma być WideCharToString albo ToolTip: array [0..1024] of WideChar; ma być Char czy coś najlepiej w Watches sobie podglądnij co masz w zmiennej ToolTip po ReadProcessMemory.

- Rejestracja:prawie 17 lat
- Ostatnio:około 3 lata
- Lokalizacja:Szczecin
- Postów:4191
Przy założeniu, że n = 2 i poprawieniu typów, efekt jest taki sam. U mnie ToolTip
pokazuje w MessageBoxie same znaki zapytania, a po konwersji wykonanej jak u Ciebie - jest to pusty string. Trudno, ja sam nie mam ochoty dociekać co i jak, a Ty bez 64 bitowego systemu też nie dojdziesz. Może ktoś inny się jeszcze właczy w ten wątek i wymyśli uniwersalny kod, który zadziała też pod 64 bitowym systemem. Niemniej jednak - jeszcze raz, dziękuje Tobie za czas jaki poświęciłeś aby to w ogóle działąlo chociaż na 32 bitowym systemie kompilując pod Delphi.
- Rejestracja:około 18 lat
- Ostatnio:11 miesięcy
Zawaliliście cały wątek niedziałającymi kodami w Delphi nie pytając nawet autora w jakim języku pisze. A najprawdopodobniej chodzi o C#, ew. C++.

- Rejestracja:prawie 17 lat
- Ostatnio:około 3 lata
- Lokalizacja:Szczecin
- Postów:4191
No to już autor powinien sprecyzowac. Nie nasz wina. A w WinAPI oczywiście równie dobrze można pisać i pod Delphi. Natomiast podałem też link do kodu w C++ gdzie ze screenshotów wynika, że działa. I jest sprawdzanie czy mamy do czynienia z uruchomieniem pod 64 bitowym systemem oraz odpowiednią reakcją na ten fakt.

- Rejestracja:ponad 21 lat
- Ostatnio:około 9 godzin
@Azarien: jaką funkcję do tego proponujesz i czy masz może pomysł jak pod Delphi rozwiązać problem poruszony w wątku dla 64 `itowego systemu.
Funkcja jest dobra (IsWow64Process
), tylko jej użycie nie.
Nie mam pod ręką gotowego przykładu, ale należy użyć jej tak:
• jeśli nasz program jest 64-bitowy (a to możemy sprawdzić jakimś ifdefem, albo sizeof(pointer)
), to jest oczywiste, że system jest 64-bitowy. inaczej program by się przecież nie uruchomił...
• jeśli nasz program jest 32-bitowy, to system może być 32-, albo 64-bitowy. i teraz sprawdzamy tak:
· jeśli funkcji IsWow64Process nie da się załadować, to system jest na pewno 32-bitowy.
· jeśli funkcja zwraca true, to system jest 64-bitowy,
· jeśli funkcja zwraca false, to system jest 32-bitowy.
IsWow64Process()
zwraca true
tylko dla programu 32-bitowego uruchomionego pod systemem 64-bitowym. czyli w programach 64-bitowych zwraca false
.

- Rejestracja:prawie 17 lat
- Ostatnio:około 3 lata
- Lokalizacja:Szczecin
- Postów:4191
@Markness: jak uważasz, ale może nie poddawaj się. Kody, które podal @kAzek działają na systemie 32 bitowym. Tak on twierdzi, a ja nie mam podstaw by mu nie wierzyć. Poza tym kod w C++ z pod jednego, z adresów. które podałem również powinien działać, jeżeli wierzyć autorowi dołaczonych do wpisu na stronie zrzutów ekranowych. W tym drugim przypadku uniknął byś konieczności tlumaczenia tego z Delphi.
Hint
nazywa;