 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
corrupt
Joined: 29 Dec 2004 Posts: 2446
|
Posted: Wed Feb 22, 2006 4:44 am Post subject: |
|
|
I haven't done much testing of the functionality for closing the applications but this is an alternate method for selecting the drive that seems to work ok:
| Code: |
; original code by Serenity
; modified drive selection method
Gui, Add, Button, x22 y80 w75 h23 gCloseApps, OK
Gui, Add, Button, x103 y80 w75 h23 gGuiClose, Cancel
Gui, Add, Text, x14 y10 w180 h15 , Please choose the drive from the list:
Gui, Add, DropDownList, x16 y40 w170 h120 AltSubmit Choose1 vList1,
SplashTextOn, 200, 60,, Please wait.`n Generating a list of drives on your system...
; first get the drive letter of "MyDrive":
driveget, list, list ; all drives
stringlen, len, list
loop, %len%
{
stringleft, drive, list, 1
driveget, label, label, %drive%:
GuiControl,,List1, %drive%: %label%
d%A_Index% := drive
stringtrimleft, list, list, 1
}
If d1<>
GuiControl,Choose, List1, 1
Gui, Show, h116 w200, Choose Drive
SplashTextOff
Return
GetModuleFileNameEx( p_pid )
{
if A_OSVersion in WIN_95,WIN_98,WIN_ME
{
MsgBox, This Windows version (%A_OSVersion%) is not supported.
return
}
/*
#define PROCESS_VM_READ (0x0010)
#define PROCESS_QUERY_INFORMATION (0x0400)
*/
h_process := DllCall( "OpenProcess", "uint", 0x10|0x400, "int", false, "uint", p_pid )
if ( ErrorLevel or h_process = 0 )
{
MsgBox, [OpenProcess] failed
return
}
name_size = 255
VarSetCapacity( name, name_size )
result := DllCall( "psapi.dll\GetModuleFileNameExA", "uint", h_process, "uint", 0, "str", name, "uint", name_size )
if ( ErrorLevel or result = 0 )
MsgBox, [GetModuleFileNameExA] failed
DllCall( "CloseHandle", h_process )
return, name
}
CloseApps:
GuiControlGet, List1
mydrive := d%List1% ":"
; now get list of running programs:
WS_EX_APPWINDOW = 0x40000
WS_EX_TOOLWINDOW = 0x80
GW_OWNER = 4
WinGet, list, List
loop, %list%
{
wid := list%A_Index%
WinGet, es, ExStyle, ahk_id %wid%
if ( ( ! DllCall( "GetWindow", "uint", wid, "uint", GW_OWNER ) and ! ( es & WS_EX_TOOLWINDOW ) )
or ( es & WS_EX_APPWINDOW ) )
{
WinGet, pid, PID, ahk_id %wid%
name := GetModuleFileNameEx( pid )
; use splitpath to obtain drive letter of each app:
SplitPath, name, , , , , Drive
; close the program if drive matches:
if Drive = %mydrive%
WinClose, ahk_pid %pid%
}
}
MsgBox, Finished processing drive %mydrive%
GuiClose:
ExitApp |
Edit: fixed a couple bugs in the code I posted that prevented apps from being closed.
Last edited by corrupt on Wed Feb 22, 2006 6:03 am; edited 4 times in total |
|
| Back to top |
|
 |
Serenity
Joined: 08 Nov 2004 Posts: 1272
|
Posted: Wed Feb 22, 2006 5:01 am Post subject: |
|
|
| selioneru wrote: | | one thing though it doesn't include processes in the tray or hidden processes |
I can confirm this. Currently AutoHotkey cannot get the list of all running processes. One workaround is to use PSList to obtain the list of running processes. _________________ "Anything worth doing is worth doing slowly." - Mae West
 |
|
| Back to top |
|
 |
corrupt
Joined: 29 Dec 2004 Posts: 2446
|
Posted: Wed Feb 22, 2006 5:21 am Post subject: |
|
|
@Serenity
Should
be
| Code: | | if Drive = %mydrive%: |
in the code you posted? |
|
| Back to top |
|
 |
Serenity
Joined: 08 Nov 2004 Posts: 1272
|
Posted: Wed Feb 22, 2006 5:37 am Post subject: |
|
|
| corrupt wrote: | @Serenity
Should
be
| Code: | | if Drive = %mydrive%: |
in the code you posted? |
Thanks. I just tested it, it should be: | Code: | | if Drive = %mydrive% |
SplitPath returns the drive letter and colon. The variable mydrive shouldn't need the last colon if it was added earlier in the script:
| Code: | if label = MyDrive ; specify the label of your drive here
mydrive = %drive%: |
This version uses the Task Manager to retrieve the list of all running processes. I've tested it and it works. :) I've removed some of the msgboxes from Shimanov's GetModuleFileNameEx function to prevent interruptions.
| Code: | driveget, list, list ; get all drives on filesystem
stringlen, len, list
loop, %len%
{
stringleft, drive, list, 1
driveget, label, label, %drive%:
if label = MYDRIVE ; specify the label of your drive here
mydrive = %drive%:
stringtrimleft, list, list, 1
}
; Task Manager needs to be running for this to work, with the Processes tab selected
ControlGet, List, List, Col2, SysListView321, Windows Task Manager ; get the pids
Loop, Parse, List, `n
{
name := getmodulefilenameex(A_LoopField)
; use splitpath to obtain drive letter of each app:
SplitPath, name, , , , , Drive
; close the program if drive matches:
if Drive = %mydrive%
WinClose, ahk_pid %pid%
}
return
GetModuleFileNameEx( p_pid )
{
if A_OSVersion in WIN_95,WIN_98,WIN_ME
{
MsgBox, This Windows version (%A_OSVersion%) is not supported.
return
}
/*
#define PROCESS_VM_READ (0x0010)
#define PROCESS_QUERY_INFORMATION (0x0400)
*/
h_process := DllCall( "OpenProcess", "uint", 0x10|0x400, "int", false, "uint", p_pid )
name_size = 255
VarSetCapacity( name, name_size )
result := DllCall( "psapi.dll\GetModuleFileNameExA", "uint", h_process, "uint", 0, "str", name, "uint", name_size )
DllCall( "CloseHandle", h_process )
return, name
} |
_________________ "Anything worth doing is worth doing slowly." - Mae West
 |
|
| Back to top |
|
 |
corrupt
Joined: 29 Dec 2004 Posts: 2446
|
Posted: Wed Feb 22, 2006 6:01 am Post subject: |
|
|
| Serenity wrote: | The variable mydrive shouldn't need the last colon if it was added earlier in the script:
| Code: | if label = MyDrive ; specify the label of your drive here
mydrive = %drive%: |
|
Good point. I'll change the code I posted for consistency. |
|
| Back to top |
|
 |
Serenity
Joined: 08 Nov 2004 Posts: 1272
|
Posted: Wed Feb 22, 2006 6:56 am Post subject: |
|
|
I've written a parser for PSList to obtain only the pids of the running processes:
| Code: | ; Get list of running processes with PSList http://www.sysinternals.com/Utilities/PsList.html
RunWait %comspec% /c pslist -t >list.txt, , Hide
Loop, Read, list.txt
{
if A_LoopReadLine not contains Russinovich,Sysinternals,Process,Name,Idle
Loop, parse, A_LoopReadLine, %A_Space%
{
if A_LoopField !=
count++
if count = 2 ; pid column
{
MsgBox, %A_LoopField% ; pid
count=
break
}
}
} |
If you want to use PSList instead of the Task Manager, replace the section that uses Task Manager with this:
| Code: | RunWait %comspec% /c pslist -t >list.txt, , Hide
Loop, Read, list.txt
{
if A_LoopReadLine not contains Russinovich,Sysinternals,Process,Name,Idle
Loop, parse, A_LoopReadLine, %A_Space%
{
if A_LoopField !=
count++
if count = 2 ; pid column
{
name := getmodulefilenameex(A_LoopField) ; MsgBox, %A_LoopField%
; use splitpath to obtain drive letter of each app:
SplitPath, name, , , , , Drive
if Drive = %mydrive%
WinClose, ahk_pid %pid%
count=
break
}
}
}
return |
_________________ "Anything worth doing is worth doing slowly." - Mae West
 |
|
| Back to top |
|
 |
shimanov
Joined: 25 Sep 2005 Posts: 610
|
Posted: Wed Feb 22, 2006 7:37 am Post subject: |
|
|
Here is another piece of the puzzle:
note: EnumProcesses and GetModuleFileNameEx are available with Windows NT 4.0, 2000, XP, etc.
| Code: | Gui, Add, ListView, x5 y5 w400 h200, PID|file name
Gui, Show, x50 y50, EnumProcesses experiment
total := EnumProcesses( pid_list )
loop, parse, pid_list, |
LV_Add( "", A_LoopField, GetModuleFileNameEx( A_LoopField ) )
LV_ModifyCol( 1, "Integer Sort AutoHdr" )
LV_ModifyCol( 2, "AutoHdr" )
return
GuiClose:
ExitApp
EnumProcesses( byref r_pid_list )
{
if A_OSVersion in WIN_95,WIN_98,WIN_ME
{
MsgBox, This Windows version (%A_OSVersion%) is not supported.
return, false
}
pid_list_size := 4*1000
VarSetCapacity( pid_list, pid_list_size )
status := DllCall( "psapi.dll\EnumProcesses", "uint", &pid_list, "uint", pid_list_size, "uint*", pid_list_actual )
if ( ErrorLevel or !status )
return, false
total := pid_list_actual//4
r_pid_list=
address := &pid_list
loop, %total%
{
r_pid_list := r_pid_list "|" ( *( address )+( *( address+1 ) << 8 )+( *( address+2 ) << 16 )+( *( address+3 ) << 24 ) )
address += 4
}
StringTrimLeft, r_pid_list, r_pid_list, 1
return, total
}
GetModuleFileNameEx( p_pid )
{
if A_OSVersion in WIN_95,WIN_98,WIN_ME
{
MsgBox, This Windows version (%A_OSVersion%) is not supported.
return
}
h_process := DllCall( "OpenProcess", "uint", 0x10|0x400, "int", false, "uint", p_pid )
if ( ErrorLevel or h_process = 0 )
return
name_size = 255
VarSetCapacity( name, name_size )
result := DllCall( "psapi.dll\GetModuleFileNameExA", "uint", h_process, "uint", 0, "str", name, "uint", name_size )
DllCall( "CloseHandle", h_process )
return, name
} |
|
|
| Back to top |
|
 |
Serenity
Joined: 08 Nov 2004 Posts: 1272
|
Posted: Wed Feb 22, 2006 7:51 am Post subject: |
|
|
Fantastic! Now we can get list of running processes without using the Task Manager or an external utility. :) _________________ "Anything worth doing is worth doing slowly." - Mae West
 |
|
| Back to top |
|
 |
corrupt
Joined: 29 Dec 2004 Posts: 2446
|
Posted: Wed Feb 22, 2006 8:40 am Post subject: |
|
|
Nice . Here's an attempt at putting the pieces together so far:
| Code: |
; code by Serenity, shimanov
; pieced together and modified by corrupt
Gui, Add, Button, x22 y80 w75 h23 gCloseApps, OK
Gui, Add, Button, x103 y80 w75 h23 gGuiClose, Cancel
Gui, Add, Text, x14 y10 w180 h15 , Please choose the drive from the list:
Gui, Add, DropDownList, x16 y40 w170 h120 Choose1 vList1,
SplashTextOn, 200, 60,, Please wait.`n Generating a list of drives on your system...
driveget, list, list ; all drives
stringlen, len, list
loop, %len%
{
stringleft, drive, list, 1
If drive <> A
driveget, label, label, %drive%:
GuiControl,,List1, %drive%: %label%
stringtrimleft, list, list, 1
}
GuiControl,Choose, List1, 1
Gui, Show, h116 w200, Choose Drive
SplashTextOff
Return
CloseApps:
GuiControlGet, List1
stringleft, listres, List1, 2
mydrive := listres
total := EnumProcesses( pid_list )
loop, parse, pid_list, |
{
lname := GetModuleFileNameEx( A_LoopField )
If lname<>
{
; use splitpath to obtain drive letter of each app:
SplitPath, lname, , , , , Drive
; close the program if drive matches:
if Drive = %mydrive%
{
WinClose, ahk_pid %A_LoopField%
Process, WaitClose, %A_LoopField%, 4
If (ErrorLevel)
{
Process, Close, %A_LoopField%
Process, WaitClose, %A_LoopField%, 4
If (ErrorLevel)
MsgBox, %lname% is not responding. `nPlease manually close this application
}
}
}
}
MsgBox, Finished processing drive %mydrive%
GuiClose:
ExitApp
EnumProcesses( byref r_pid_list )
{
if A_OSVersion in WIN_95,WIN_98,WIN_ME
{
MsgBox, This Windows version (%A_OSVersion%) is not supported.
return, false
}
pid_list_size := 4*1000
VarSetCapacity( pid_list, pid_list_size )
status := DllCall( "psapi.dll\EnumProcesses", "uint", &pid_list, "uint", pid_list_size, "uint*", pid_list_actual )
if ( ErrorLevel or !status )
return, false
total := pid_list_actual//4
r_pid_list=
address := &pid_list
loop, %total%
{
r_pid_list := r_pid_list "|" ( *( address )+( *( address+1 ) << 8 )+( *( address+2 ) << 16 )+( *( address+3 ) << 24 ) )
address += 4
}
StringTrimLeft, r_pid_list, r_pid_list, 1
return, total
}
GetModuleFileNameEx( p_pid )
{
if A_OSVersion in WIN_95,WIN_98,WIN_ME
{
MsgBox, This Windows version (%A_OSVersion%) is not supported.
return
}
h_process := DllCall( "OpenProcess", "uint", 0x10|0x400, "int", false, "uint", p_pid )
if ( ErrorLevel or h_process = 0 )
return
name_size = 255
VarSetCapacity( name, name_size )
result := DllCall( "psapi.dll\GetModuleFileNameExA", "uint", h_process, "uint", 0, "str", name, "uint", name_size )
DllCall( "CloseHandle", h_process )
return, name
}
|
Edit:
- removed label retrieval for A: drive to drastically speed up drive detection process.
- removed a few unnecessary variables |
|
| Back to top |
|
 |
selioneru
Joined: 19 Feb 2006 Posts: 8
|
Posted: Wed Feb 22, 2006 11:49 pm Post subject: |
|
|
Thanks SO Much! this rocks! Bravo! verrry cool Props to Serenity and corrupt! |
|
| Back to top |
|
 |
corrupt
Joined: 29 Dec 2004 Posts: 2446
|
Posted: Thu Feb 23, 2006 1:27 am Post subject: |
|
|
...and shimanov...  |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4517 Location: Boulder, CO
|
Posted: Thu Feb 23, 2006 1:50 am Post subject: |
|
|
| There is one process I cannot close. Even the console command "kill -9" fails, with the error: Access is denied. I have to close it manually from the Task Manager. Is there an easy way to grant the script the right to kill or make the process mortal? |
|
| Back to top |
|
 |
corrupt
Joined: 29 Dec 2004 Posts: 2446
|
Posted: Thu Feb 23, 2006 2:07 am Post subject: |
|
|
| Laszlo wrote: | | There is one process I cannot close. Even the console command "kill -9" fails, with the error: Access is denied. I have to close it manually from the Task Manager. Is there an easy way to grant the script the right to kill or make the process mortal? |
I'm not too sure... Maybe try using RunAs with kill using the Administrator account? Maybe there another process that has to be closed first? |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4517 Location: Boulder, CO
|
Posted: Thu Feb 23, 2006 4:33 am Post subject: |
|
|
| I am administrator, but still I tried RunAs, without success. I think it is some security settings of that particular service, because from the highest authority (Task Manager) it can be killed with a mouse click on the End button (and confirm my killer intensions). |
|
| Back to top |
|
 |
PhiLho
Joined: 27 Dec 2005 Posts: 6723 Location: France (near Paris)
|
Posted: Thu Feb 23, 2006 2:01 pm Post subject: |
|
|
There is the PSKill utility from SysInternals, but I don't know if it is more potent than NT's kill... _________________
vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2") |
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|