Showing posts with label Windows. Show all posts
Showing posts with label Windows. Show all posts

Monday, April 14, 2014

Refresh tray icons - How to remove dead tray icon after killing a program/process

Sometime you  just need to automate something, like running a script, killing a program, refreshing something...
Killing a program from a script, sometime, have an unwanted side effect: the tray icon of this program wont go away until you move your mouse over it.
So after, say, 10 run of the script, you find yourself with 10 copy of the same (dead) icons.


The solution seam easy: just move your mouse over the dead icons, and they will go away.
But after years of applying this same old solution, I got tired, and I started looking for a better way :-)

And I found it: I found an AutoHotKey script that refresh the trayicons, removing the dead one.
There are various version of this specific script, the one I found seem to works perfectly on Win7 x64 (it's supposed to works even on x32 system, but I didn't try it) 
I would like to credit the original author, but I don't remember the specific forum/website where I downloaded this specific version (I downloaded a lot of ahk script before finding one that worked...)

Here are the download links:

Here is the source code (formatting by  http://codeformatter.blogspot.it/  and  http://prettyprinter.de/module.php?name=PrettyPrinter)
 tray_iconCleanup()  
 tray_icons()  
 {  
   static TB_BUTTONCOUNT := 0x0418, TB_GETBUTTON := 0x0417  
   array := []  
   array[0] := ["sProcess","toolTip","nMsg","uID","idx","idn","Pid","hwnd","sClass","hIcon"]  
   Index := 0  
   detectHiddenWindows_old := a_detectHiddenWindows  
   detectHiddenWindows, on  
   trayWindows := "Shell_TrayWnd,NotifyIconOverflowWindow"  
   loop, parse, trayWindows, csv  
   {  
     winGet, taskbar_pid, PID, ahk_class %a_loopField%  
     hProc := dllCall( "OpenProcess", "Uint", 0x38, "int", 0, "Uint", taskbar_pid )  
     pProc := dllCall( "VirtualAllocEx", "Uint", hProc, "Uint", 0, "Uint", 32, "Uint", 0x1000, "Uint", 0x4 )  
     idxTB := tray_getTrayBar()  
     sendMessage, %TB_BUTTONCOUNT%, 0, 0, ToolbarWindow32%idxTB%, ahk_class %a_loopField%  
     loop, %errorLevel%  
     {  
       sendMessage, %TB_GETBUTTON%, a_index-1, pProc, ToolbarWindow32%idxTB%, ahk_class %a_loopField%  
       varSetCapacity( btn,32,0 ), varSetCapacity( nfo,32,0 )  
       dllCall( "ReadProcessMemory", "Uint", hProc, "Uint", pProc, "Uint", &btn, "Uint", 32, "Uint", 0 )  
       iBitmap := numGet( btn, 0 )  
       idn := numGet( btn, 4 )  
       Statyle := numGet( btn, 8 )  
       if dwData := numGet( btn,12,"Uint" )  
       iString := numGet( btn,16 )  
       else dwData := numGet( btn,16,"int64" ), iString := numGet( btn,24,"int64" )  
       dllCall( "ReadProcessMemory", "Uint", hProc, "Uint", dwData, "Uint", &nfo, "Uint", 32, "Uint", 0 )  
       if numGet( btn,12,"Uint" )  
       {  
         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,"Uint" ), nMsg := numGet( nfo,12,"Uint" )  
       winGet, pid, PID, ahk_id %hwnd%  
       winGet, sProcess, ProcessName, ahk_id %hwnd%  
       winGetClass, sClass, ahk_id %hwnd%  
       varSetCapacity( sTooltip,128 ), varSetCapacity( wTooltip,128*2 )  
       dllCall( "ReadProcessMemory", "Uint", hProc, "Uint", iString, "Uint", &wTooltip, "Uint", 128*2, "Uint", 0 )  
       dllCall( "WideCharToMultiByte", "Uint", 0, "Uint", 0, "str", wTooltip, "int", -1, "str", sTooltip, "int", 128, "Uint", 0, "Uint", 0 )  
       idx := a_index-1  
       toolTip := a_isUnicode ? wTooltip : sTooltip  
       Index++  
       for a,b in array[0]  
       array[Index,b] := %b%  
     }  
     dllCall( "VirtualFreeEx", "Uint", hProc, "Uint", pProc, "Uint", 0, "Uint", 0x8000 )  
     dllCall( "CloseHandle", "Uint", hProc )  
   }  
   detectHiddenWindows, %detectHiddenWindows_old%  
   return array  
 }  
 tray_iconCleanup()  
 {  
   /*  
   remove orphan icons ( Their processes have been killed )  
   */  
   tray_icons := tray_icons()  
   for index in tray_icons  
   {  
     ifEqual,index,0,continue  
     if ( tray_icons[index, "sProcess"] = "" )  
     tray_iconRemove( tray_icons[index, "hwnd"], tray_icons[index, "uID"],"", tray_icons[index, "hIcon"] )  
   }  
 }  
 tray_iconRemove( hwnd, uID, nMsg = 0, hIcon = 0, nRemove = 0x2 )  
 {  
   /*  
   NIM_DELETE := 0x00000002  
   typedef struct _NOTIFYICONDATA {  
     DWORD cbSize; x00  
     hwnd hwnd; x04  
     UINT uID; x0c/d12  
     UINT uFlags; x10/d16  
     UINT uCallbackMessage; x14/d20  
     HICON hIcon; x18/d24  
     TCHAR szTip[64]; x20 ( UNICODE )  
     DWORD dwState; xa0  
     DWORD dwStateMask; xa4  
     TCHAR szInfo[256]; xa8 ( UNICODE )  
     union {  
       UINT uTimeout; x01a8  
       UINT uVersion; x01a8  
     };  
     TCHAR szInfoTitle[64]; x01ac ( UNICODE )  
     DWORD dwInfoFlags; x022c  
     GUID guidItem; ( 128bits ) x0230  
     HICON hBalloonIcon; x023c  
     ;end x0244  
   } NOTIFYICONDATA, *PNOTIFYICONDATA;  
   MSDN:  
   http://msdn.microsoft.com/en-us/library/windows/desktop/bb773352%28v=vs.85%29.aspx  
   */  
   varSetCapacity( nid,size := 936+4*a_ptrSize )  
   numPut( size, nid, 0, "uint" )  
   numPut( hwnd, nid, a_ptrSize )  
   numPut( uID, nid,a_ptrSize*2, "uint" )  
   numPut( 1|2|4, nid,a_ptrSize*3, "uint" )  
   numPut( nMsg , nid,a_ptrSize*4, "uint" )  
   numPut( hIcon, nid,a_ptrSize*5, "uint" )  
   return dllCall( "shell32\Shell_NotifyIconA", "Uint", nRemove, "Uint", &nid )  
 }  
 tray_iconHide( idn, bHide = true )  
 {  
   static TB_HIDEBUTTON := 0x404, WM_SETTINGCHANGE := 0x001A  
   idxTB := tray_getTrayBar()  
   sendMessage, %TB_HIDEBUTTON%, idn, bHide, ToolbarWindow32%idxTB%, ahk_class Shell_TrayWnd  ;NotifyIconOverflowWindow  
   sendMessage, %WM_SETTINGCHANGE%, 0, 0, , ahk_class Shell_TrayWnd  
 }  
 tray_iconDelete( idx )  
 {  
   static TB_DELETEBUTTON := 0x416, WM_SETTINGCHANGE := 0x001A  
   idxTB := tray_getTrayBar()  
   sendMessage, %TB_DELETEBUTTON%, idx - 1, 0, ToolbarWindow32%idxTB%, ahk_class Shell_TrayWnd  
   sendMessage, %WM_SETTINGCHANGE%, 0, 0, , ahk_class Shell_TrayWnd  
 }  
 tray_iconMove( idxOld, idxNew )  
 {  
   static TB_MOVEBUTTON := 0x452  
   idxTB := tray_getTrayBar()  
   sendMessage, %TB_MOVEBUTTON%, idxOld - 1, idxNew - 1, ToolbarWindow32%idxTB%, ahk_class Shell_TrayWnd  
 }  
 tray_getTrayBar()  
 {  
   detectHiddenWindows_old := a_detectHiddenWindows  
   detectHiddenWindows, on  
   controlGet, hParent, hwnd,, TrayNotifyWnd1 , ahk_class Shell_TrayWnd  
   controlGet, hChild , hwnd,, ToolbarWindow321, ahk_id %hParent%  
   loop  
   {  
     controlGet, hwnd, hwnd,, ToolbarWindow32%a_index%, ahk_class Shell_TrayWnd  
     if !hwnd  
     break  
     else if ( hwnd = hChild )  
     {  
       idxTB := a_index  
       break  
     }  
   }  
   detectHiddenWindows, %detectHiddenWindows_old%  
   return idxTB  
 }  

Monday, December 16, 2013

Android: How to share folder over WiFi and access them from a Windows computer without rooting Android (using a Samba/SMB/CIFS server, a virtual computer, and some port-mapping)

Today I set myself a goal: being able to share a folder over WiFi on my Galaxy S4 (stock, not rooted) and access this shared folder from my computer (running Windows 7).

Everybody will tell you that's not possible because Windows can only access an SMB/CIFS share on the standard TCP port 445, and on a non rooted Android device a normal app can't open port in the 1-1024 range.

On a rooted Android you can use an app like Samba Filesharing for Android and this will start a SMB server on port 445 on you Androi device.
But you need a rooted device, and I don't want to root my Galaxy S4 (not yet).

So on a non-rooted device you can install another SMB server app, like Samba Server, but in this way the SMB service will work on non-standard port, like the TCP port 7777. And Windows computer can't connect to a shared folder on a TCP port other than 445.

But this is only a simple TCP connection on a standard TCP port, so I thought I should be able to map/forward a TCP connection from a port 445 to a port 7777 (the one used by Samba Server), and make it work.

Usually mapping/forwarding a TCP port is a very simple thing on windows, there are tons of free application that can forward a TCP connection.

So the plan looks simple: I will start a connection from my Windows PC to some IP on port 445, then on this IP I should accept this connection and forward it to the IP of the smartphone, on the port 7777.


The question is: where can I setup a service that listen for connections on port 445?
  • On my computer? no, because I need the standard file sharing service up and running to access the shared folder on my smartphone.
  • On my NAS? no, because a nas is meaningless if I can't access it's shared folders.
  • On my router? no, this is not going to work: routers normally will forward connection from WAN to LAN, not from LAN to LAN.
  • On a pfSense running in a Virtualbox? I tried it, but it seem that pfSense have similar limitation of other routers, so forwarding from LAN to LAN doesent works.
  • On a router running DD-WRT? Maybe (I don't know)... as of today the router I use to experiment with DD-WRT it's sitting in my closet waiting for some exciting networking experiment... but not his one: I don't want another hotbox  powered on 24h/day just for accessing a single shared folder on my smartphone...

So I went for another Windows installation, running in VirtualBox.
It turned out that Windows 7 is very attached to it's 445 port, it took me some time to convince Windows to close the 445 TCP port.
But with the help of some post, and some cycle of service-stopping/reboot activity, I've been able to get a Windows PC that doesn't listen on port 445 :-)

Here is a screenshot of the setting/services I modified/disabled in this installation, probably it's not necessary to disable all those service, but I didn't have the time to disable them 1-by-1 and reboot every time...
As you can see from TCPView running in the lower right corner, there are no services listening on port 445 :-)


The rest is easy, fire up a TCP port mapper/forwarder, listen on port 445, forward to port 7777 and you will be able to access the shared folder on your non-rooted android device, from a Windows PC :-)

Here is the portmapper running on my virtualpc
In this experiment I used PortTunnel this is a very-very-old version of the software (when there was free version) but it still works today :-)

As you can guess from the screenshot the IP address of my smartphone is 192.168.157.101, and the IP of my virtualPC is 192.168.157.107.

And in the following screenshot you can see my main computer (192.168.157.110), connected to the shared folder on my Galaxy S4 (192.168.157.101)  (trough the portmapping on the virtualpc (192.168.157.107) )
The address that my computer see is 192.168.157.107, but the data come from the smartphone  (192.168.157.101) trough the portmapping.

and here is a folder with some image, seen from my main PC
and here is the same folder on the smartphone

Here is the configuration of the samba server on the smartphone


For this experiment I've tried different Samba server on android, the only one that worked in this configuration is this one, called Samba Server.

So now I can access the shared folder on my non-rooted Galaxy S4.
There is only a tiny issue... it's a bit slow.
Copying data from the PC to the shared folder transfer data at a speed of 1.2 Mb/sec.
Maybe this is due to the software used for the port-mapping...but now I don't have time to try other port-mapping tools.

Anyway... It's not fats, but it works! :-)