Hi coders,
I owe much AHK, I am still learning and I can't solve some simple problems.
Well, this time I want to extract a program's tray icon in systray. I tried a few scripts to do that such as Sean's TrayIcon.ahk, Lexicos' MI.ahk, Maul.Esel's SaveHImage2File.ahk, Majkinetor's W i n library. I read through many topics but I didn't find a working example. I also tried a script posted by Tic here <!-- m -->http://www.autohotke...topic31642.html<!-- m -->, I didn't achieve it to work. For a noob like me problems look impossible to overcome. Would somebody help me about it?
[SOLVED]Extract programs icon in systray
Started by
kenn
, Jan 24 2012 07:52 PM
16 replies to this topic
#1
-
Posted 24 January 2012 - 07:52 PM
Which program's icon do you want to extract? Have you succeeded to identify either PID, program path, or window handle that owns the icon? And after extracting it, what do you want to do with it? Just displaying it on GUI or save it? Please be more specific.
#2
-
Posted 24 January 2012 - 08:19 PM
It's a dictionary called Lingoes. I want to automate it using its icon but at first I need to extract its icon in order to use it in image search. <!-- m -->http://www.autohotke.../topic7905.html<!-- m -->
<!-- m -->http://www.autohotke...ic.php?p=448190<!-- m -->
<!-- m -->http://www.autohotke...pic.php?t=47856<!-- m -->
<!-- m -->http://www.autohotke...topic21991.html<!-- m -->
<!-- m -->http://www.autohotke...topic26042.html<!-- m -->
In these topics it's mentioned. I also asked it as a reference to newbies here.
<!-- m -->http://www.autohotke...ic.php?p=448190<!-- m -->
<!-- m -->http://www.autohotke...pic.php?t=47856<!-- m -->
<!-- m -->http://www.autohotke...topic21991.html<!-- m -->
<!-- m -->http://www.autohotke...topic26042.html<!-- m -->
In these topics it's mentioned. I also asked it as a reference to newbies here.
#3
-
Posted 24 January 2012 - 08:46 PM
Just take a screenshot and crop the icon.I need to extract its icon in order to use it in image search
Also it sounds like you want to execute menu items of the system tray icon. In that case, I suggest to learn manipulating window messages. Here is a good tutorial. [pictorial] Find WM_COMMAND parameter with Winspector
#4
-
Posted 24 January 2012 - 09:26 PM
Thanks. I found this here <!-- m -->http://www.autohotke...ic33955-60.html<!-- m -->
I can extract associated icon from exe file with it, it fulfilled my aim to some extent but what I want to do is to extract systray icon as it is. I ll keep pushing it.
I can extract associated icon from exe file with it, it fulfilled my aim to some extent but what I want to do is to extract systray icon as it is. I ll keep pushing it.
ptr := A_PtrSize =8 ? "ptr" : "uint" ;for AHK Basic FileName := "C:\Program Files\Lingoes\Translator2\lingoes.exe" hIcon := DllCall("Shell32\ExtractAssociatedIcon" (A_IsUnicode ? "W" : "A"), ptr, DllCall("GetModuleHandle", ptr, 0, ptr), str, FileName, "ushort*", lpiIcon, ptr) ;only supports 32x32 Gui, Margin, 20, 20 Gui, Add, Text, w32 h32 hwndmypic1 0x3 ; 0x3 = SS_ICON SendMessage, STM_SETICON := 0x0170, hIcon, 0,, Ahk_ID %mypic1% Gui, Show Return GuiClose: GuiEscape: ExitApp
#5
-
Posted 24 January 2012 - 10:11 PM
may i ask why you want that?
you already mentioned the TrayIcon.ahk, which seems to be all you need to automate icon interaction but without unreliable ImageSearchs.
you already mentioned the TrayIcon.ahk, which seems to be all you need to automate icon interaction but without unreliable ImageSearchs.
#6
-
Posted 24 January 2012 - 10:25 PM
may i ask why you want that?
It's kind of turned out to be challenging to me, I should solve it.
I get hwnd of tray icon with TrayIcon.ahk, and I am trying to get bitmap of the icon with gdip but it fails. Isn't it possible to get icons handle with TrayIcon.ahk? Or is it something different thing that I don't know of?
pToken := Gdip_Startup() pBitmap := Gdip_BitmapFromHWND() Gdip_SaveBitmapToFile(pBitmap, "Full sized image.png") Gdip_DisposeImage(pBitmap) Gdip_Shutdown(pToken)
#7
-
Posted 25 January 2012 - 10:32 AM
Icon and Bitmap are two different image formats.
Try translate this code into AHK. Converting Icon to Bitmap (HICON -> HBITMAP) - Windows programming - Forums at ProgrammersHeaven.com.
Try translate this code into AHK. Converting Icon to Bitmap (HICON -> HBITMAP) - Windows programming - Forums at ProgrammersHeaven.com.
#8
-
Posted 25 January 2012 - 10:42 AM
Thanks a lot Guest Things are getting clearer for me. I ll try to convert it into AHK. It's my homework. I hope I won't fail.
#9
-
Posted 25 January 2012 - 11:16 AM
I struggled to convert that code into AHK, I did it, when I used it to extract icon's bitmap I got no result. While searching for forum here <!-- m -->http://www.autohotke...ic.php?p=489897<!-- m --> I found this moded code from Sean's screencapture.ahk. It's used to capture cursor in screen. I inserted the systay icon handle that I grabbed with TrayIcon.ahk into code. I tried many variations. It looks hopeless. Would somebody guide me in the right direction?Icon and Bitmap are two different image formats.
Try translate this code into AHK. Converting Icon to Bitmap (HICON -> HBITMAP) - Windows programming - Forums at ProgrammersHeaven.com.
Here is the code that extracts cursor into clipboard
#z:: VarSetCapacity(mi, 20, 0), mi := Chr(20) DllCall("GetCursorInfo", "Uint", &mi) bShow := NumGet(mi, 4) ;1 ==> cursor is visible (MSDN) hCursor := NumGet(mi, 8) ;cursor handle xCursor := NumGet(mi,12) ;not really needed for this script, but might want later yCursor := NumGet(mi,16) ;same as ^ If bShow && hCursor:=DllCall("CopyIcon", "Uint", hCursor) { VarSetCapacity(ni, 20, 0) DllCall("GetIconInfo", "Uint", hCursor, "Uint", &ni) bIcon := NumGet(ni, 0) ;is cursor ==> false, is icon ==> true xHotspot := NumGet(ni, 4) ;I think this is the click location yHotspot := NumGet(ni, 8) hBMMask := NumGet(ni,12) ;again not used in script hBMColor := NumGet(ni,16) ;same as ^ ;the tiny part I added starts here mDC := DllCall("CreateCompatibleDC", "Uint", 0) ;make a DC compatible with screen hBM := CreateDIBSection(mDC, 32, 32) ;I think this makes a blank bitmap based on mDC (except dimensions) oBM := DllCall("SelectObject", "Uint", mDC, "Uint", hBM) ;put hBM into the DC but save original DC in oBM ;ends here DllCall("DrawIcon", "Uint", mDC, "int", 0, "int", 0, "Uint", hCursor) ;draw the icon into the DC DllCall("DestroyIcon", "Uint", hCursor) ;clear the memory of uneeded objects If hBMMask DllCall("DeleteObject", "Uint", hBMMask) If hBMColor DllCall("DeleteObject", "Uint", hBMColor) } DllCall("SelectObject", "Uint", mDC, "Uint", oBM) ;switch back to original DC then delete DllCall("DeleteDC", "Uint", mDC) SetClipboardData(hBM) ;put the image on the clipboard return CreateDIBSection(hDC, nW, nH, bpp = 32, ByRef pBits = "") { NumPut(VarSetCapacity(bi, 40, 0), bi) NumPut(nW, bi, 4) NumPut(nH, bi, 8) NumPut(bpp, NumPut(1, bi, 12, "UShort"), 0, "Ushort") NumPut(0, bi,16) Return DllCall("gdi32\CreateDIBSection", "Uint", hDC, "Uint", &bi, "Uint", 0, "UintP", pBits, "Uint", 0, "Uint", 0) } SetClipboardData(hBitmap) { DllCall("GetObject", "Uint", hBitmap, "int", VarSetCapacity(oi,84,0), "Uint", &oi) hDIB := DllCall("GlobalAlloc", "Uint", 2, "Uint", 40+NumGet(oi,44)) pDIB := DllCall("GlobalLock", "Uint", hDIB) DllCall("RtlMoveMemory", "Uint", pDIB, "Uint", &oi+24, "Uint", 40) DllCall("RtlMoveMemory", "Uint", pDIB+40, "Uint", NumGet(oi,20), "Uint", NumGet(oi,44)) DllCall("GlobalUnlock", "Uint", hDIB) DllCall("DeleteObject", "Uint", hBitmap) DllCall("OpenClipboard", "Uint", 0) DllCall("EmptyClipboard") DllCall("SetClipboardData", "Uint", 8, "Uint", hDIB) DllCall("CloseClipboard") }
#10
-
Posted 26 January 2012 - 04:16 PM
This requires. GDI+ standard library 1.45 by tic
ptr := A_PtrSize =8 ? "ptr" : "uint" ;for AHK Basic FileName := A_WinDir "\notepad.exe" hIcon := DllCall("Shell32\ExtractAssociatedIcon" (A_IsUnicode ? "W" : "A") , ptr, DllCall("GetModuleHandle", ptr, 0, ptr) , str, FileName , "ushort*", lpiIcon , ptr) ;only supports 32x32 SavehIconAsBMP(hIcon, A_ScriptDir "\notepad.bmp") SavehIconAsBMP(hIcon, sFile) { if pToken := Gdip_Startup() { pBitmap := Gdip_CreateBitmapFromHICON(hIcon) Gdip_SaveBitmapToFile(pBitmap, sFile) Gdip_DisposeImage(pBitmap) Gdip_Shutdown(pToken) return true } return false }Also bitmap does not support transparent background. Why do you want to save icon as bitmap?
#11
-
Posted 26 January 2012 - 08:39 PM
Thank you for your interest and the post. I tried that kind of scripts, they work. Unfortunately it doesn't answer my aim. What I am trying to do is to reach systray icons by handle. I just noticed that it's not that easy.
First, what I get with TrayIcon.ahk is not the icon's handle in systray but the main application's handle So it didn't work in my case.
I found the solution in AutoIt's forum. Here it is <!-- m -->http://www.autoitscr... ... ns-solved/<!-- m -->
I hope somebody converts it into AHK
First, what I get with TrayIcon.ahk is not the icon's handle in systray but the main application's handle So it didn't work in my case.
I found the solution in AutoIt's forum. Here it is <!-- m -->http://www.autoitscr... ... ns-solved/<!-- m -->
I hope somebody converts it into AHK
#12
-
Posted 26 January 2012 - 08:58 PM
At last I solved it!! Thanks to Sean and HotkeyIt and Lexikos.
I only changed return value of TrayIcon.ahk. While I was searching I met RefreshTray() function by HotkeyIt, subsequently I noticed moded version of TrayIcon.ahk by HotkeyIt. When I combine what I read for a week in the forums, I noticed I was only one step away from it. Then I tried following moded script, it gave me the correct handle of the icon.
I only changed return value of TrayIcon.ahk. While I was searching I met RefreshTray() function by HotkeyIt, subsequently I noticed moded version of TrayIcon.ahk by HotkeyIt. When I combine what I read for a week in the forums, I noticed I was only one step away from it. Then I tried following moded script, it gave me the correct handle of the icon.
TrayIcons() ;will remove dead icons msgbox, % TrayIcons(sExeName = "lingoes.exe") TrayIcons(sExeName = "lingoes.exe") { DetectHiddenWindows,% DHW:=A_DetectHiddenWindows ? "On" : "On" WinGet, pidTaskbar, PID, ahk_class Shell_TrayWnd hProc:= DllCall("OpenProcess", "Uint", 0x38, "int", 0, "Uint", pidTaskbar) pProc:= DllCall("VirtualAllocEx", "Uint", hProc, "Uint", 0, "Uint", 32, "Uint", 0x1000, "Uint", 0x4) idxTB:= GetTrayBar() ControlGet,chWnd,HWND,,ToolbarWindow32%idxTB%, ahk_class Shell_TrayWnd ErrorLevel:=DllCall("SendMessage","UPTR",chWnd,"UInt", 0x418, "UPTR",0,"UPTR", 0,"UPTR") ; TB_BUTTONCOUNT Loop, %ErrorLevel% { DllCall("SendMessage","UPTR",chWnd,"UInt",0x417,"UPTR",A_Index-1,"UPTR",pProc) ; TB_GETBUTTON VarSetCapacity(btn,32,0), VarSetCapacity(nfo,32,0) DllCall("ReadProcessMemory", "UPTR", hProc, "UPTR", pProc, "UPTR", &btn, "Uint", 32, "Uint", 0) iBitmap := NumGet(btn, 0) idn := NumGet(btn, 4) Statyle := NumGet(btn, 8) If dwData := NumGet(btn,12) iString := NumGet(btn,16) Else dwData := NumGet(btn,16,"int64"), iString:=NumGet(btn,24,"int64") DllCall("ReadProcessMemory", "UPTR", hProc, "UPTR", dwData, "UPTR", &nfo, "Uint", 32, "Uint", 0) If NumGet(btn,12) hWnd := NumGet(nfo, 0) , uID := NumGet(nfo, 4) , nMsg := NumGet(nfo, 8) , hIcon := NumGet(nfo,20) Else hWnd := NumGet(nfo, 0,"int64"), uID:=NumGet(nfo, 8), nMsg:=NumGet(nfo,12) If (!DllCall("IsWindow","UPTR",hwnd)) { IconsToRemove.=hwnd "." uID "." Continue } WinGet, pid, PID, ahk_id %hWnd% WinGet, sProcess, ProcessName, ahk_id %hWnd% WinGetClass, sClass, ahk_id %hWnd% If !sExeName || (sExeName = sProcess) || (sExeName = pid) VarSetCapacity(sTooltip,128), VarSetCapacity(wTooltip,128*2) , DllCall("ReadProcessMemory", "UPTR", hProc, "UPTR", iString, "UPTR", &wTooltip, "Uint", 128*2, "Uint", 0) , A_IsUnicode ? (sToolTip:=StrGet(&wToolTip)) : DllCall("WideCharToMultiByte", "Uint", 0, "Uint", 0, "str", wTooltip, "int", -1, "str", sTooltip, "int", 128, "Uint", 0, "Uint", 0) , sTrayIcons .= "idx: " . A_Index-1 . " | idn: " . idn . " | Pid: " . pid . " | uID: " . uID . " | MessageID: " . nMsg . " | hWnd: " . hWnd . " | Class: " . sClass . " | Process: " . sProcess . "`n" . " | Tooltip: " . sTooltip . "`n" } Loop,Parse,IconsToRemove,. If !Mod(A_Index,2) RemoveTrayIcon(hwnd,A_LoopField) else hwnd:=A_LoopField DllCall("VirtualFreeEx", "UPTR", hProc, "UPTR", pProc, "Uint", 0, "Uint", 0x8000) DllCall("CloseHandle", "UPTR", hProc) DetectHiddenWindows,% DHW Return hIcon ; [color=red]<--I only added this [/color] }I extract icon by inserting icon handle into Lexikos' ExtractIcon() function in Menu Icons v2 script
hIcon1 :=66528 STM_SETICON := 0x0170 Gui, Margin, 20, 20 Gui, Add, Text, w64 h64 hwndmypic1 0x3 SendMessage, STM_SETICON, hIcon1, 0,, Ahk_ID %mypic1% Gui, Show Return GuiClose: ExitApp ExtractIcon(Filename, IconNumber, IconSize) { ;most of the code is from Menu Icons v2.21 ;written by Lexikos http://www.autohotkey.com/forum/topic21991.html static ExtractIconEx, Ptr, PtrP if !Ptr Ptr := (A_PtrSize = 8) ? "ptr" : "uint" If !PtrP PtrP := (A_PtrSize = 8) ? "uptr*" : "uint*" ; LoadImage is not used.. ; ..with exe/dll files because: ; it only works with modules loaded by the current process, ; it needs the resource ordinal (which is not the same as an icon index), and ; ..with ico files because: ; it can only load the first icon (of size %IconSize%) from an .ico file. ; If possible, use PrivateExtractIcons, which supports any size of icon. if (IconSize != 16 && IconSize != 32) if A_OSVersion in WIN_7,WIN_XP,WIN_VISTA,WIN_2003,WIN_2000 if DllCall("PrivateExtractIcons", "str", Filename, "int", IconNumber-1, "int", IconSize, "int", IconSize, PtrP, h_icon, "uint*", 0, "uint",1, "uint",0,"int") return h_icon if !ExtractIconEx ExtractIconEx := DllCall("GetProcAddress" , ptr, DllCall("GetModuleHandle", str, "shell32", ptr) , A_IsUnicode ? "astr":"str" ; Always an ANSI string. , "ExtractIconEx" . (A_IsUnicode ? "W":"A"), ptr) ; Use ExtractIconEx, which only returns 16x16 or 32x32 icons. ; if DllCall(ExtractIconEx, "str", Filename, "int", IconNumber-1, PtrP, h_icon, PtrP, h_icon_small, "uint", 1) if DllCall(ExtractIconEx, "str", Filename, "int", IconNumber-1, PtrP, h_icon, PtrP, h_icon_small, "uint", 1) { SysGet, SmallIconSize, 49 ; Use the best-fit size; delete the other. Defaults to small icon. if (IconSize <= SmallIconSize) { DllCall("DestroyIcon", ptr, h_icon) h_icon := h_icon_small } else DllCall("DestroyIcon", ptr, h_icon_small) ; I think PrivateExtractIcons resizes icons automatically, ; so resize icons returned by ExtractIconEx for consistency. if (h_icon && IconSize) h_icon := DllCall("CopyImage", ptr, h_icon, "uint", 1, "int", IconSize, "int", IconSize, "uint", 4|8, ptr) } return h_icon ? h_icon : 0 }
#13
-
Posted 30 January 2012 - 06:51 PM
I might take a look at beginning to incorporate some of this into the gdi+ library (although not really gdi+ it could be helpful)
#14
-
Posted 30 January 2012 - 07:17 PM
Hi Tic, thanks a lot for your interest and kindness. It'd be very nice to have a standalone trayicon extraction script, I hope you generalize it and make a multi-functional icon script.
#15
-
Posted 30 January 2012 - 07:40 PM