Converting B3D Userlib/decls to BMax

BlitzMax Forums/BlitzMax Beginners Area/Converting B3D Userlib/decls to BMax

.rIKmAN.(Posted 2011) [#1]
Hey,

I am in the process of converting an old Blitz3D project over to Bmax, and it's going quite well as I'm picking up the new syntax etc.

However, the project used a userlib/decls to access some API functions for reading/writing a process' memory, and obviously these aren't in BMax.
The userlib is "Read/Write Process Memory" by SKN[AC]3 and can be found here: http://www.blitzbasic.com/codearcs/codearcs.php?code=1206

I have had a go at getting it working in BMax using "Extern" statements and searching through the forums for tidbits of similar info I can hack together - however I have now tied myself in knots.

Can anyone tell me:

1) Is it possible to do this same thing in BMax?
I ask as I have read info (searching the forums here) saying it is not possible and will give MAV's, but then how did it work in B3D?

2) Would anyone be kind enough to give me some code to show the syntax to convert it, and I could then use this example to wrap the remaining ones myself.

I managed to get an open processes PID displayed in the debuglog correctly, and I could kill a process (using ther PID), but then it all went pair shaped when I tried to add Reading/Writing of the memory addresses

Thanks in advance for any help.

Last edited 2011


col(Posted 2011) [#2]
An extract from the userlib file...
.lib "user32.dll"
Pmem_FindWindow%(class%,name$):"FindWindowA"
Pmem_GetWindowThreadProcessId%(hwnd%,processid*):"GetWindowThreadProcessId"
Pmem_GetClassName%(hwnd%,classname*,max%):"GetClassNameA"


Bmax equivalent :-
Global user32:Int = LoadLibraryA("user32.dll")

Global Pmem_FindWindow:Int( class:Int , name:byte ptr )"win32" = GetProcAddress( user32 , "FindWindowA" )
Global Pmem_GetWindowThreadProcessId:Int( hwnd:Int , processid:Byte Ptr )"win32" = GetProcAddress( user32 , "GetWindowThreadProcessId" )
Global Pmem_GetClassName:Int( hwnd:Int , classname:Byte Ptr , Max_:Int )"win32" = GetProcAddress( user32 , "GetClassNameA" )


Its a start. You may want to browse through the modules. On the right on the main editor browse down through 'Home/Projects/Modules/pub.mod/win32.mod......

Theres plenty of examples in there for you to do exactly what you want to do :D

Last edited 2011


.rIKmAN.(Posted 2011) [#3]
col that's awesome, just the start I needed!

One more quick question, I notice in the b3d userlib he wrapped the pmem_ functions inside his own.

ie.
Function OpenProcessMemory(processid,access=983040 Or 1048576 Or 4095)
Return Pmem_OpenProcess(access,False,processid)
End Function

Do I need to do this also or can I just use the original Pmem_ function directly with Max? (as apposed to b3d)

Thanks for your reply mate, appreciated! :)


col(Posted 2011) [#4]
EDIT :- You dont need to wrap it in the same he has, but he must have had a reason for it so...
To be safe and save me a longer explanation for it :D, I'd do the same as he has.

Any help, just shout :D

Last edited 2011


.rIKmAN.(Posted 2011) [#5]
Got any links I could read for the long explanation, or search terms I could google?
As I said I wanna learn and do it myself, I just need to know the right place to look :)

I'll get my head buried in this tonight and see what I can get going, and if (when?) I get stumped I'll give this thread a nudge :)

Cheers!


col(Posted 2011) [#6]
If all you're doing is porting it over then using the little snippets above should be enough, but do check out the win32 modules though if something isnt working, I guarantee you will have problems when it comes to strings.. For eg..

LoadLibraryA takes a Byte Ptr for the strings type, but
LoadLibraryW takes a $w for its string type or $z.

You'll get MAVs when youre using the wrong one :D

Use SuperStrict all the way through or at least use Strict. Maybe grab yourself a copy of the WindowsSDK too for documentation.

But you say that you're just porting it over, then it should be real straight forward. A nights work ;)


.rIKmAN.(Posted 2011) [#7]
Maybe for you...lol!

Yeah I will need strings (footy manager game) so I'm in for a night of MAVs :P

Thanks for the help, I'm on it :)

Last edited 2011


Kryzon(Posted 2011) [#8]
From what I've seen around, the main reason for mapping the functions with custom ones with blitz code is to change the name (put them all under the same naming convention, like "myLib_").
A secondary reason is establishing a default value for certain parameters (like that 'access' parameter). You can't set default values inside DECLS with Blitz3D, so you need to map some functions to your own.

Using the LoadLibraryA\LoadLibraryW and loading the DLL is one way (preferred by many for being easier, and in my opinion it's more intuitive: you're loading the DLL into memory and harnessing the functions from it).
Since the User32 is part of the Windows core, you can also use a BMax Extern:

Extern "Win32"
	Function FindWindow:Int(class:Int, name:String)
	Function GetWindowThreadProcessId:Int(hwnd:Int, processid:Byte Ptr)
	Function GetClassName:Int(hwnd:Int, classname:Byte Ptr, max:Int)
EndExtern

Externs are very useful for interfacing with the OS's API or even C\C++ libraries that have an equivalent "Extern C" block. I also think you can use default values for these extern functions, so you don't need to map them.
I'm not familiar enough with Externs to explain them fully, but you can download GMan's Irrlicht wrapper as it wraps the entire engine using Externs with .cpp and .h glue files, using BMax's Types as classes. It's really amazing.

Further info:
http://blitzbasic.com/Community/posts.php?topic=87986
http://blitzbasic.com/Community/posts.php?topic=85563

Last edited 2011


.rIKmAN.(Posted 2011) [#9]
Yeah I spotted earlier most code examples I was looking at declared the API Functions using Extern blocks, I figured it was so you could add your own code to the function rather than use it "as-is" in the DLL, but I'm still learning this stuff so any additional info is great.

I was scratching my head earlier wondering why I was getting 'Unhandled Memory Exception Error' using FindWindow when I was sure everything was corrent - I had to put 'End' at the end to stop it, that's how noob I am haha!

Thanks for those links Kryzon, I'll have a read shortly. :)

Last edited 2011


kfprimm(Posted 2011) [#10]
I'd just like to throw in that many of the Windows API functions and constants are already declared in PUB.Win32.

Check to see if those function exist before you bother to declare them.

Last edited 2011


col(Posted 2011) [#11]
Only the Windows API calls work with the Extern"win32" command??

Any other .dll needs to be included using LoadLibraryA, oh wait! I'm sure someone made use of importing the .a decl files too to save not loading the dll? but I cant find the posts.


kfprimm(Posted 2011) [#12]
http://blitzbasic.com/Community/posts.php?topic=41803#469834

You may need to grab pexports from somewhere off the net because if I remember right, it is no longer included in MinGW.


col(Posted 2011) [#13]
Clears that up :D

When i started porting the whole of Dx9/D3DX to BMax I experimented with that route, but was put off because of the ease of simply LoadLibrary the .dll, create the function pointers to the real functions and it works seamlessly, it just seemed soooo much easier for me at the time.

:D


.rIKmAN.(Posted 2011) [#14]
Thanks for the Pub.Win32 info, I'll have a check if I hit any problems.

I'm in the situation you were in back then col.
I'm gonna get it working using LoadLibraryA, then once that's done start again using Extern and hopefully at the end of that I'll have wrapped my head around it and understand it all :)

Right now I'm fighting with MaxIDE CE, keeps greying out the compile buttons when I get an error (not all errors) and forcing me to restart so gonna have to go back to the stock IDE for now.

Onwards and upwards :)

Last edited 2011


col(Posted 2011) [#15]
You'll also notice that when using LoadLibrary, and you stop the code at runtime to kick in the debugger, the function variables will contain an address value, so you can see which functions are actually linked to a valid address.

Careful though as the value could also be an invalid pointer value, but I think its the same value every time for an undefined function pointer, a low number. If the values are all around the same value, but obviously different from each other, then you can assume its linked to the address in the dll, and you're in :D then write a line to call and test it :p

Using the 'Extern' method you don't get to see the function pointer value, just helps with debugging, like leaving an A or W off of the end of the function name :D


.rIKmAN.(Posted 2011) [#16]
Well I've been fiddling for the last couple of hours while watching tv, and have found that it seems LoadLibraryA doesn' seem to want to load 'win32.dll'

Global user32:Int = LoadLibraryA("user32.dll")
If user32 Print "user32"

Global kernel32:Int = LoadLibraryA("kernel32.dll")
If kernel32 Print "kernel32"

Global win32:Int = LoadLibraryA("win32.dll")
If win32 Print "win32"

End


If you run the following code you see user32 and kernel32 get loaded fine, but win32 doesn't.

What am I doing wrong?

EDIT: Doh, just realised the API calls are in kernel32.dll anyway, and win32 is just the naming convention.
Also I had to set the access variables which I found on MSDN.

Phew, bedtime, thanks for everyones help so far! :)

Last edited 2011