Declaring API externs with structures

BlitzMax Forums/BlitzMax Programming/Declaring API externs with structures

Blueapples(Posted 2006) [#1]
I am attempting to call some Win32 API functions which take structures (types). Has anyone had any experience with this? I haven't been able to get it to work...

SuperStrict

Import "-lkernel32"

Const TH32CS_SNAPPROCESS:Int = 2
Const MAX_PATH:Int = 260

Type PROCESSENTRY32
    Field dwSize:Int
    Field cntUsage:Int
    Field th32ProcessID:Int
    Field th32DefaultHeapID:Int
    Field th32ModuleID:Int
    Field cntThreads:Int
    Field th32ParentProcessID:Int
    Field pcPriClassBase:Int
    Field dwFlags:Int
    Field szExeFile:String
End Type  

Extern "Win32"
	Function WinExec(lpCmdLine:Byte Ptr,nCmdShow:Int)="WinExec@8"
	Function CreateToolhelp32Snapshot:Int(lFlags:Int, lProcessID:Int)
	Function ProcessFirst(hSnapShot:Int, uProcess:PROCESSENTRY32 Ptr)
	Function ProcessNext(hSnapShot:Int, uProcess:PROCESSENTRY32 Ptr)
	Function CloseHandle(hPass:Int)
End Extern


Error:

Compile Error: Illegal pointer type
[Projects/max/dllp/process_list.bmx;24;2]
Build Error: failed to compile Projects/max/dllp/process_list.bmx
Process complete


I also tried declaring ProcessFirst and ProcessNext with integers as their second argument, which obviously doesn't work either.


EOF(Posted 2006) [#2]
Something like this I think:
SuperStrict
Framework brl.basic

Import "-lkernel32"

Const TH32CS_SNAPPROCESS:Int = 2
Const MAX_PATH:Int = 260

Type PROCESSENTRY32
    Field dwSize:Int
    Field cntUsage:Int
    Field th32ProcessID:Int
    Field th32DefaultHeapID:Int
    Field th32ModuleID:Int
    Field cntThreads:Int
    Field th32ParentProcessID:Int
    Field pcPriClassBase:Int
    Field dwFlags:Int
    Field szExeFile:String
End Type  

Extern "Win32"
	Function WinExec(lpCmdLine:Byte Ptr,nCmdShow:Int) = "WinExec@8"
	Function CreateToolhelp32Snapshot:Int(lFlags:Int, lProcessID:Int)
	Function ProcessFirst(hSnapShot:Int, uProcess:Byte Ptr)
	Function ProcessNext(hSnapShot:Int, uProcess:Byte Ptr)
	Function CloseHandle(hPass:Int)
End Extern

' Global pe:PROCESSENTRY32=New PROCESSENTRY32
' result=ProcessFirst(0,Byte Ptr(pe))



skidracer(Posted 2006) [#3]
hmm, the last thread with this code must have been lost as I posted working version but can't now find it. to get you started here is:

.. see below

now you need to create a new processentry32 struct, assign dwSize to sizeof(processentry32), rename your Process functions to Proces32 and you should be away...


skidracer(Posted 2006) [#4]
SuperStrict

Const TH32CS_SNAPPROCESS:Int = 2

Type PROCESSENTRY32

	Field dwSize:Int
	Field cntUsage:Int
	Field th32ProcessID:Int
	Field th32DefaultHeapID:Int
	Field th32ModuleID:Int
	Field cntThreads:Int
	Field th32ParentProcessID:Int
	Field pcPriClassBase:Int
	Field dwFlags:Int
	Field szExeFile:Byte,b1:Byte,b2:Byte,b3:Byte	'4 + 256=260 bytes for path
	Field p0:Long,p1:Long,p2:Long,p3:Long
	Field p4:Long,p5:Long,p6:Long,p7:Long
	Field p8:Long,p9:Long,pa:Long,pb:Long
	Field pc:Long,pd:Long,pe:Long,pf:Long
	Field q0:Long,q1:Long,q2:Long,q3:Long
	Field q4:Long,q5:Long,q6:Long,q7:Long
	Field q8:Long,q9:Long,qa:Long,qb:Long
	Field qc:Long,qd:Long,qe:Long,qf:Long
	Field th32MemoryBase:Int
	Field th32AccessKey:Int
End Type  

Extern "Win32"
	Function WinExec(lpCmdLine:Byte Ptr,nCmdShow:Int)
	Function CreateToolhelp32Snapshot:Int(lFlags:Int, lProcessID:Int)
	Function Process32First(hSnapShot:Int, uProcess:Byte Ptr)
	Function Process32Next(hSnapShot:Int, uProcess:Byte Ptr)
	Function CloseHandle(hPass:Int)
End Extern

Local p:PROCESSENTRY32=New PROCESSENTRY32
p.dwSize=SizeOf(processentry32)
Local h:Int=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0)
process32First(h,p)
DebugLog "szExeFile="+String.FromCString(Varptr p.szExeFile)
While process32Next(h,p)
	DebugLog " szExeFile="+String.FromCString(Varptr p.szExeFile)
Wend


Note the need to declare the arguments in extern functions as type byte ptr to correctly pass the bmx object as a struct.


Blueapples(Posted 2006) [#5]
Cool, this seems to be working perfectly. I have a question though, is there any way that I could use an array for the padding instead of several Long fields? I tried to do it like...

...
	Field szExeFile:Byte
	Field szExeFileArray:Byte[MAX_PATH - 1]


But the SizeOf() for the resulting structure is only 52 instead of 304. I suspect this is because the array does not really allocate memory for each slot but rather is a dynamic one. So it seems there's no way to do the padding with an array...