Page 1 of 1
Calling a windows function from purebasic
Posted: Wed Mar 24, 2021 3:46 pm
by dangerfreak
My OS is Windows 10 (64 bit) and I want to call a windows library function via purebasic itself and with the built-in assembler. It works perfectly using the 32bit compiler of Purebasic, but not with the 64bit compiler.
This is the code (it's just an example for the windows "Beep" function):
Code: Select all
EnableExplicit
#lib=0
Global *address
If OpenLibrary(#lib,"kernel32.dll")=0
Debug("dll not found")
End
EndIf
ExamineLibraryFunctions(#lib)
While NextLibraryFunction()
If LibraryFunctionName()="Beep"
*address=LibraryFunctionAddress()
Break
EndIf
Wend
CloseLibrary(#lib)
If *address=0
Debug("address not found")
End
EndIf
Debug("calling from purebasic - works with 32 and 64bit compiler")
CallFunctionFast(*address,100,500) ; works!
Delay(1000)
Debug("calling from assembler - only works with 32 bit compiler")
!push 500 ; beep len in ms
!push 200 ; beep frequency
!CALL [p_address]
Delay(1000)
End
What could be the reason? Any ideas?
PLEASE: Don't ask for the "why". Just tell me, what is wrong with the code. Thank you very much.
Re: Calling a windows function from purebasic
Posted: Wed Mar 24, 2021 5:01 pm
by netmaestro
First and foremost, CallFunctionFast is crushingly limited in every way you can imagine. It was written before Prototypes and Imports were available in PureBasic. Please forget you ever learned of it. I hereby release you from any and all responsibilities, real and imagined, related to your discovery of this profoundly deprecated function. I show two correct implementations:
Code: Select all
; Using Prototypes
OpenLibrary(0, "kernel32.dll")
Prototype Beep(frequency.l, duration.l)
Global Beepit.Beep = GetFunction(0, "Beep")
Beepit(500,500)
CloseLibrary(0)
; Using Imports
Import "" ; when it's kernel32 that's all you need but you'd normally code Import "kernel32.lib" or such
Beep(frequency.l, duration.l)
EndImport
Beep(500,500)
I'm not sure of the implementation in asm, you could read the generated asm from my examples and see what's there. Alternatively you could ask Wilbert or Helle and you'd get a comprehensive answer pretty quick. Those two are amazing asm coders. Idle too. (if I forgot someone, sorry about that. At least you know I'm not mad at you or I'd remember your name

.)
Re: Calling a windows function from purebasic
Posted: Wed Mar 24, 2021 5:11 pm
by Jeff8888
Note Windows X64 uses registers for first four subroutine parameters, so this fix to your code works.
Debug("calling from assembler - only works with 32 bit compiler")
!mov rdx,500 ; beep len in ms
!mov rcx,800 ; beep frequency
!CALL [p_address]
See Microsoft doc:
https://docs.microsoft.com/en-us/cpp/bu ... w=msvc-160
Re: Calling a windows function from purebasic
Posted: Wed Mar 24, 2021 5:19 pm
by RASHAD
From the previous posts of the fellows
Code: Select all
EnableExplicit
#lib=0
Global *address
If OpenLibrary(#lib,"kernel32.dll")=0
Debug("dll not found")
End
EndIf
*address = GetFunction(#lib, "Beep")
CloseLibrary(#lib)
If *address=0
Debug("address not found")
End
EndIf
Debug("calling from purebasic - works with 32 and 64bit compiler")
CallFunctionFast(*address,100,500) ; works!
Delay(1000)
Debug("calling from assembler - only works with 32 bit compiler")
CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
!push 500 ; beep len in ms
!push 200 ; beep frequency
!CALL [p_address]
CompilerElse
!mov rdx,500 ; beep len in ms
!mov rcx,200 ; beep frequency
!CALL [p_address]
CompilerEndIf
Delay(1000)
End
Re: Calling a windows function from purebasic
Posted: Wed Mar 24, 2021 7:10 pm
by dangerfreak
Thanks @all, that really helped me a lot!
There's one question left, maybe you also know an answer for it. The following code uses windows library calls to find the address of a function (function "Beep" again). It works perfectly with the 32bit compiler, but not with the 64bit compiler (the result is 0):
Code: Select all
EnableExplicit
Global hwnd.l
Global *string
Global *address
; Get handle to library:
hwnd=GetModuleHandle_("kernel32.dll")
; Convert the string "beep" from unicode to ascii:
; (sorry, I don't know an easier way)
*string=AllocateMemory(100)
PokeS(*string,"Beep",-1,#PB_Ascii)
; get the function address - only works with the 32bit compiler of Purebasic
*address=GetProcAddress_(hwnd,*string) ; this function only works with an ascii/ansi string
Debug(*address)
If *address=0
Debug("Couldn't find function 'Beep'")
EndIf
FreeMemory(*string)
Any ideas? And is there an easier way to convert an unicode string to ascii/ansi?
Re: Calling a windows function from purebasic
Posted: Wed Mar 24, 2021 7:47 pm
by StarBootics
dangerfreak wrote:And is there an easier way to convert an unicode string to ascii/ansi?
I have stop using Window in 2009 so I can't help you with your issue. But the easiest way to create an Ascii buffer is like that
Code: Select all
*String = Ascii("Beep")
; Do your stuff with the *String buffer
FreeMemory(*String)
THe FreeMemory() call is important to avoid a Memory leak.
Best regards
StarBootics
Re: Calling a windows function from purebasic
Posted: Wed Mar 24, 2021 7:48 pm
by RASHAD
For x86 & x64
Code: Select all
EnableExplicit
Global hwnd.i
Global *string
Global *address
; Get handle to library:
hwnd = GetModuleHandle_("kernel32.dll")
; Convert the string "beep" from unicode to ascii:
; (sorry, I don't know an easier way)
*string = Ascii("Beep")
; get the function address - only works with the 32bit compiler of Purebasic
*address=GetProcAddress_(hwnd,*string) ; this function only works with an ascii/ansi string
Debug(*address)
If *address=0
Debug("Couldn't find function 'Beep'")
EndIf
FreeMemory(*string)
For x86
Code: Select all
EnableExplicit
Global hwnd.l
Global *string
Global *address
; Get handle to library:
hwnd = GetModuleHandle_("kernel32.dll")
; Convert the string "beep" from unicode to ascii:
; (sorry, I don't know an easier way)
*string = Ascii("Beep")
; get the function address - only works with the 32bit compiler of Purebasic
*address=GetProcAddress_(hwnd,*string) ; this function only works with an ascii/ansi string
Debug(*address)
If *address=0
Debug("Couldn't find function 'Beep'")
EndIf
FreeMemory(*string)
For x64
Code: Select all
EnableExplicit
Global *hwnd
Global *String
Global *address
; Get handle to library:
*hwnd = GetModuleHandle_("kernel32.dll")
*String = Ascii("Beep")
; Convert the string "beep" from unicode to ascii:
; (sorry, I don't know an easier way)
;*string=AllocateMemory(100)
;PokeS(*string,"Beep",-1,#PB_Ascii)
; get the function address - only works with the 32bit compiler of Purebasic
*address=GetProcAddress_(*hwnd,*String) ; this function only works with an ascii/ansi string
Debug(*address)
If *address=0
Debug("Couldn't find function 'Beep'")
EndIf
FreeMemory(*String)
Re: Calling a windows function from purebasic
Posted: Mon Apr 19, 2021 12:43 pm
by dangerfreak
Thanks for all your help, that solved my problem!

))
PS: Sorry for my late answer, I had some trouble with the forum.
Re: Calling a windows function from purebasic
Posted: Mon Apr 19, 2021 1:47 pm
by infratec
@Rashad
To avoid the string conversion use Import:
Code: Select all
EnableExplicit
Define hwnd.i
Define *address
Import ""
GetProcAddress.i(hwnd.i, string.p-ascii)
EndImport
; Get handle to library:
hwnd = GetModuleHandle_("kernel32.dll")
; get the function address - only works with the 32bit compiler of Purebasic
*address=GetProcAddress(hwnd, "Beep") ; this function only works with an ascii/ansi string
Debug(*address)
If *address=0
Debug("Couldn't find function 'Beep'")
EndIf
Re: Calling a windows function from purebasic
Posted: Mon Apr 19, 2021 6:52 pm
by RASHAD
Hi infratec
I was answering dangerfreak for how to convert Unicode to Ascii using PB
So he can use it anytime with registered dll or not
Or any other purpose
Thanks anyway