Windows API - program ID's

BlitzMax Forums/BlitzMax Programming/Windows API - program ID's

I am trying to come up with a way to kill specific processes, and cobbled together the following which is largely based on something by Sweenie... However, I am running into a snag that the PID returned by the code does not match up with the actual PID used by the program as shown by TaskManager.

If I use the taskmanager PID's I can successfully terminate a process, but for whatever reasons the PID's returned by the program below seem to be off a couple... Most of the time the returned value is off by 4, but it's not consistent -- sometimes it's off by 8, or even more than a hundred. There's definitely something not right, but for the life of me I can't figure out what it is.

Is there anyone who can offer some pointers to what I'm doing wrong?

Extern "win32"
	Function EnumWindows(Callbackptr:Byte Ptr,lParam)
	Function GetWindowText(hWnd,lpString:Byte Ptr,nMaxCount) = "GetWindowTextA@12"
	Function OpenProcess% (access, handleinherit, processid)
	Function TerminateProcess% (processhandle, exitcode)
	Function CloseHandle% (Objects)
	Function GetWindowThreadProcessId(hWnd:Int,ID:Byte Ptr) = "GetWindowThreadProcessId@8"
	Function GetClassName(hWnd:Int,clString:Byte Ptr,nMaxCount:Int) = "GetClassNameA@12" 
	
End Extern

Const PROCESS_TERMINATE = $1
Const PROCESS_CREATE_THREAD = $2
Const PROCESS_VM_OPERATION = $8
Const PROCESS_VM_READ = $10
Const PROCESS_VM_WRITE = $20
Const PROCESS_DUP_HANDLE = $40
Const PROCESS_CREATE_PROCESS = $80
Const PROCESS_SET_QUOTA = $100
Const PROCESS_SET_INFORMATION = $200
Const PROCESS_QUERY_INFORMATION = $400
Const SYNCHRONIZE = 1048576
Const STANDARD_RIGHTS_REQUIRED = 983040
Const PROCESS_ALL_ACCESS = 983040
Global CharBuffer:Byte[255]

Function EnumWindowsProc(hwnd,lParam)
	Local PID:Int
	GetWindowText(hwnd,CharBuffer,255)
	PID=GetWindowThreadProcessid(hwnd,Null)
	If String.FromCString(CharBuffer)<>"" Then
		' Skip empty process names (threads?)
		Print "PID: "+PID+"~t hWnd: "+hwnd+" ~t"+String.FromCString(CharBuffer)
	End If 
	If Instr(String.FromCString(CharBuffer),"Calculator") Then 
	Notify PID
'		DebugLog KillProcess(PID) '	
	End If 

	'Return True if you want to fetch the next window, return False to tell EnumWindows to stop.
	Return True
End Function

EnumWindows(EnumWindowsProc,0)

Function KillProcess (pid)
    phandle = OpenProcess (PROCESS_TERMINATE, False, pid)
    If phandle <> 0
        If TerminateProcess (phandle, 1)
            result = 1
        EndIf
        CloseHandle (phandle)
    EndIf
    Return result
End Function



Use pub.freeprocess.

(Oops, looks like my initial posting got chopped off. Fixed)

Use pub.freeprocess


I looked at that, but didn't see a way to kill an arbitrary process that wasn't launched through Blitzmax itself first... The problem is getting the process ID for the other program, not killing the process once I have it.

@xlsior: I'm not sure if vista will let any application terminate a process it has not started... I think it will be considered a security violation by the OS.

I'm not sure if vista will let any application terminate a process it has not started... I think it will be considered a security violation by the OS.


You're probably right, but this is for something I'm mainly writing for personal use, and I have no intention of downgrading to Vista any time soon...

And killing the process works fine with the code above under XP, the only problem I have is to programmatically get the correct process ID. If I look it up in taskmanager and feed that to the KillProcess function, it works like a charm.

lpdwProcessId param returns the Process ID that you need to use.

Extern "win32"
	Function EnumWindows(Callbackptr:Byte Ptr,lParam)
	Function GetWindowText(hWnd,lpString:Byte Ptr,nMaxCount) = "GetWindowTextA@12"
	Function OpenProcess% (access, handleinherit, processid)
	Function TerminateProcess% (processhandle, exitcode)
	Function CloseHandle% (Objects)
	Function GetWindowThreadProcessId(hWnd:Int,ID:Byte Ptr) = "GetWindowThreadProcessId@8"
	Function GetClassName(hWnd:Int,clString:Byte Ptr,nMaxCount:Int) = "GetClassNameA@12" 
	
End Extern

Const PROCESS_TERMINATE = $1
Const PROCESS_CREATE_THREAD = $2
Const PROCESS_VM_OPERATION = $8
Const PROCESS_VM_READ = $10
Const PROCESS_VM_WRITE = $20
Const PROCESS_DUP_HANDLE = $40
Const PROCESS_CREATE_PROCESS = $80
Const PROCESS_SET_QUOTA = $100
Const PROCESS_SET_INFORMATION = $200
Const PROCESS_QUERY_INFORMATION = $400
Const SYNCHRONIZE = 1048576
Const STANDARD_RIGHTS_REQUIRED = 983040
Const PROCESS_ALL_ACCESS = 983040
Global CharBuffer:Byte[255]

Function EnumWindowsProc(hwnd,lParam)
	Local TID:Int
	Local PID:Int
	GetWindowText(hwnd,CharBuffer,255)
	TID=GetWindowThreadProcessid(hwnd,Varptr PID)
	If String.FromCString(CharBuffer)<>"" Then
		' Skip empty process names (threads?)
		Print "PID: "+PID+"~t hWnd: "+hwnd+" ~t"+String.FromCString(CharBuffer)
	End If 
	If Instr(String.FromCString(CharBuffer),"Calculator") Then 
		Notify PID
		DebugLog KillProcess(PID) '	
	End If 

	'Return True if you want to fetch the next window, return False to tell EnumWindows to stop.
	Return True
End Function

EnumWindows(EnumWindowsProc,0)

Function KillProcess (pid)
    phandle = OpenProcess (PROCESS_TERMINATE, False, pid)
    If phandle <> 0
        If TerminateProcess (phandle, 1)
            result = 1
        EndIf
        CloseHandle (phandle)
    EndIf
    Return result
End Function

The one you was using is a Thread ID.

Aha! thank you so much!

The Win32 API sure isn't very easy to get started with. :-?

np mate