Calling a windows function from purebasic

Just starting out? Need help? Post your questions and find answers here.
dangerfreak
User
User
Posts: 32
Joined: Tue Jan 12, 2010 4:56 pm

Calling a windows function from purebasic

Post 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.
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8425
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Calling a windows function from purebasic

Post 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 :D .)
BERESHEIT
Jeff8888
User
User
Posts: 38
Joined: Fri Jan 31, 2020 6:48 pm

Re: Calling a windows function from purebasic

Post 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
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4636
Joined: Sun Apr 12, 2009 6:27 am

Re: Calling a windows function from purebasic

Post 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
Egypt my love
dangerfreak
User
User
Posts: 32
Joined: Tue Jan 12, 2010 4:56 pm

Re: Calling a windows function from purebasic

Post 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?
User avatar
StarBootics
Addict
Addict
Posts: 984
Joined: Sun Jul 07, 2013 11:35 am
Location: Canada

Re: Calling a windows function from purebasic

Post 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
Last edited by StarBootics on Wed Mar 24, 2021 9:12 pm, edited 1 time in total.
The Stone Age did not end due to a shortage of stones !
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4636
Joined: Sun Apr 12, 2009 6:27 am

Re: Calling a windows function from purebasic

Post 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)
Egypt my love
dangerfreak
User
User
Posts: 32
Joined: Tue Jan 12, 2010 4:56 pm

Re: Calling a windows function from purebasic

Post by dangerfreak »

Thanks for all your help, that solved my problem! :-)))

PS: Sorry for my late answer, I had some trouble with the forum.
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Calling a windows function from purebasic

Post 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
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4636
Joined: Sun Apr 12, 2009 6:27 am

Re: Calling a windows function from purebasic

Post by RASHAD »

Hi infratec
I was answering dangerfreak for how to convert Unicode to Ascii using PB :wink:
So he can use it anytime with registered dll or not
Or any other purpose
Thanks anyway
Egypt my love
Post Reply