Can someone with winapi experience look at this code and see why it gets errors?

Blitz3D Forums/Blitz3D Programming/Can someone with winapi experience look at this code and see why it gets errors?

Mike Yurgalavage(Posted 2004) [#1]
here's some code to get the list of running process IDs, but there's a slight 'issue' in that I seem to be missing something with the process name (it says 'illegal type conversion'). I think the Process32First/Next functions are overwriting something?

You should find the process in this list IDs match those in Task Manager, at least!


; -----------------------------------------------------------------------------
; Create or open existing kernel32.decls file in userlibs folder and place
; these lines in it (uncommented!)...
; -----------------------------------------------------------------------------
;
; .lib "kernel32.dll"
;
; CreateToolhelp32Snapshot% (flags, th32processid)
; Process32First% (snapshot, entry*)
; Process32Next% (snapshot, entry*)
; CloseHandle% (object)
;
; -----------------------------------------------------------------------------

Const MAX_PATH = 264
Const TH32CS_SNAPHEAPLIST = $1
Const TH32CS_SNAPPROCESS = $2
Const TH32CS_SNAPTHREAD = $4
Const TH32CS_SNAPMODULE = $8
Const TH32CS_SNAPALL = TH32CS_SNAPHEAPLIST Or TH32CS_SNAPPROCESS Or TH32CS_SNAPTHREAD Or TH32CS_SNAPMODULE
Const TH32CS_INHERIT = $80000000
Const INVALID_HANDLE_VALUE = -1
Const SizeOf_PE32 = 296

Type PROCESSENTRY32
Field dwSize
Field cntUsage
Field th32ProcessID
Field th32DefaultHeapID
Field th32ModuleID
Field cntThreads
Field th32ParentProcessID
Field pcPriClassBase
Field dwFlags
Field szExeFile$ [MAX_PATH]
End Type

snap = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0)

If snap

Proc32.PROCESSENTRY32 = New PROCESSENTRY32
Proc32\dwSize = SizeOf_PE32

If Process32First (snap, Proc32)

Print "Process ID: " + Proc32\th32ProcessID

While Process32Next (snap, Proc32)
Print "Process ID: " + Proc32\th32ProcessID
Print "----> Parent process ID: " + Proc32\th32ParentProcessID
Print Proc32\szExeFile ; Illegal type conversion?
Wend

EndIf

CloseHandle (snap)

EndIf

Print "Hit ENTER..."
Input ()
End

;-------------- end of code---------------------


thanks,
best,
mike


soja(Posted 2004) [#2]
Well, it's giving you that error becuase you've declared szExeFile to be an array of strings, and Print doesn't know how to handle arrays.

What the ProcessSentry32 structure needs for szExeFile is just a character array of MAX_PATH characters -- in other words, a plain bank will do. Unfortunately, you can't just create an instance of your PROCESSENTRY32 type and say "Proc32\szExeFile = CreateBank(MAX_PATH)", because the memory created would not be contiguous, and Windows would overwrite the bank address and probably other memory of your program... so...

The best thing to do in this case would probably be to create a bank of 296 bytes, and fill in each item manually with PokeInt and such. Then read the exefile string with peekbyte starting at offset 33 or such. Make sense?


Mike Yurgalavage(Posted 2004) [#3]
to soja-

thanks for the reply soja. the explanation does make sense but i regret that i am at a loss how to do what you suggested. where would the bank be created at and when/where would it be filled and how would i access the bank to display the array of strings? i am simply trying to get it to list each of the running processes (like in the windows taskbar). this has been an incredible headache. i guess i am learning from it! i thought that perhaps there was a blitz bug or something preventing this code from working, but it just might be what you are saying. i hope you don't mind replying to this again! i have noticed that you have helped many others with code problems. thanks again!

best,
mike


soja(Posted 2004) [#4]
I'm glad to help.

Basically, when you pass a struct (C terminology for a custom type) to a DLL, it's just a particular chunk of memory with a certain size. When you create an instance of the PROCESSENTRY32 type, you are creating the chuck of memory. But instead of thinking of it as having a bunch of fields with values, just think of all the values crammed together into one memory chunk.

So, the first 9 parameters are all expected to be DWORDS or LONGS (32 bits each which is the same as a Blitz Int, so that works out just fine). The last parameter is expected to be an array of MAX_PATH (264) TCHARs. A TCHAR is the same as a CHAR which is just 1 byte. So if you add up the number of bytes needed by each parameter, here's what you get:

4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 264 = 300 bytes
(See the MSDN documentation for the PROCCESSENTRY32 structure. I guess you forgot one byte becuase your SizeOf_PE32 = 296...? Or maybe I added one too many.)

Anyway, this means that you can now create your memory chunk to store this in and get it ready to pass to the Windows API:
Proc32 = CreateBuffer(300)

And then you procede to fill it up with the "in" parts of it (which I think is just the first parameter, right?):
PokeInt(Proc32, 0, BankSize(Proc32)) ; dwSize

Then make the call to Process32First/Next.

Then you can read what it gets back. Something like:
cntUsage = PeekInt(Proc32, 4) ; Offset at 4th byte -- read 4 bytes (sizeof Int)
th32ProcessID = PeekInt(Proc32, 8)
th32DefaultHeapID = PeekInt(Proc32, 12)
;...etc...

...and then when you get to the last bit, everything from byte 36 to the end of the bank will correspond to szExeFile. You'll have to do something like this:
offset = 36
Repeat
    char = Peekbyte(Proc32, offset)
    offset = offset + 1
    s$ = s$ + Chr$(char)
Until char = 0


Does this help you a bit? Is anything unclear?

(Warning -- the code I typed from memory and didn't test it.)


Mike Yurgalavage(Posted 2004) [#5]
thanks soja. i'll see if i can patch this into the code already and try it out and see if i can get it to work. thanks again for your help. it seems clear and easy. i'll try not to bug you further unless i get stuck. also, how do you guys print your code on the forum like that (green text with black background?) i'd like to know how so that i can post the code for others to examine that way.

thanks,
mike


Mike Yurgalavage(Posted 2004) [#6]
Soja, I got it to work! I listed the final code below. I wish that I could display the code segments like you do (black with green text) in this forum but i don't know how!

anywayz, here it is-

thanks,
mike


; -----------------------------------------------------------------------------
; Create or open existing kernel32.decls file in userlibs folder and place
; these lines in it (uncommented!)...
; -----------------------------------------------------------------------------
;
; .lib "kernel32.dll"
;
; CreateToolhelp32Snapshot% (flags, th32processid)
; Process32First% (snapshot, entry*)
; Process32Next% (snapshot, entry*)
; CloseHandle% (object)
;
; -----------------------------------------------------------------------------

Const MAX_PATH = 264
Const TH32CS_SNAPHEAPLIST = $1
Const TH32CS_SNAPPROCESS = $2
Const TH32CS_SNAPTHREAD = $4
Const TH32CS_SNAPMODULE = $8
Const TH32CS_SNAPALL = TH32CS_SNAPHEAPLIST Or TH32CS_SNAPPROCESS Or TH32CS_SNAPTHREAD Or TH32CS_SNAPMODULE
Const TH32CS_INHERIT = $80000000
Const INVALID_HANDLE_VALUE = -1
Const SizeOf_PE32 = 296

Type PROCESSENTRY32
Field dwSize
Field cntUsage
Field th32ProcessID
Field th32DefaultHeapID
Field th32ModuleID
Field cntThreads
Field th32ParentProcessID
Field pcPriClassBase
Field dwFlags
Field szExeFile$ [MAX_PATH]
End Type


snap = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0)

If snap
;Print snap
Proc32=CreateBank(SizeOf_PE32)
PokeInt(Proc32, 0, BankSize(Proc32)) ; dwSize


If Process32First (snap, Proc32)
;cntUsage = PeekInt(Proc32, 4) ; Offset at 4th byte -- read 4 bytes (sizeof Int)
;th32ProcessID = PeekInt(Proc32, 8)
;th32DefaultHeapID = PeekInt(Proc32, 12)

Print "Process ID: " + th32ProcessID
Print

While Process32Next (snap, Proc32)
dwSize=PeekInt(Proc32,0)
cntUsage=PeekInt(Proc32,4)
th32ProcessID=PeekInt(Proc32,8)
th32DefaultHeapID=PeekInt(Proc32,12)
th32ModuleID=PeekInt(Proc32,16)
cntThreads=PeekInt(Proc32,20)
th32ParentProcessID=PeekInt(Proc32,24)
pcPriClassBase=PeekInt(Proc32,28)
dwFlags=PeekInt(Proc32,32)
offset = 36
Repeat
char = PeekByte(Proc32, offset)
offset = offset + 1
szExeFile$ = szExeFile$ + Chr$(char)
Until char = 0
szExeFile$=Left$(szExeFile$,Len(szExeFile$)-1)
Print szExeFile$
Print "Process ID: " + th32ProcessID
Print "----> Parent process ID: " + th32ParentProcessID
szExeFile$=""

Input()
Wend
Input()

EndIf

CloseHandle (snap)

EndIf

Print "Hit ENTER..."
Input ()
End


Tom(Posted 2004) [#7]
Hi,

Nice work!

To highlight code in green, use these tags but take out the *, I put them in in case BB tries to format the message :)

[CODE*] your code here [/CODE*]