Page 1 of 1

ProcedureCDLL Return Result

Posted: Mon Sep 23, 2024 4:46 pm
by Leo1958
I've wrote a DLL Which works quite well within an external program. The problem I'm having is the
return value (Result) from the routine after providing a param. variable to the procedure in the DLL.

See example code below

ProcedureCDLL.i PeekData(D)
Glabal V.i,R.i,V.i
For V=0 To D
R=Array(V)
Next V
Result=R
ProcedureReturn Result
EndProcedure

The above code will crash the program I'm running the DLL from.

Whereas this code works

ProcedureDLL.i PeekSpectrumData_1(100)
Result=Array(100)
ProcedureReturn Result
EndProcedure

I'm sure it's something I'm not doing, any pointers would be helpful.

p.s. My journey with Pure Basic has only just started


Thanks in advance

Leo

Re: ProcedureCDLL Return Result

Posted: Mon Sep 23, 2024 5:19 pm
by jacdelad
1 Hi!
2. Please use code tags
3. There is no function Array() in PureBasic.
4. Don't use global within procedures, use Protected. Also "glabal"...
5. We need a runable code for the DLL and the calling program. Even if this means the code crashes.
...

Re: ProcedureCDLL Return Result

Posted: Mon Sep 23, 2024 5:22 pm
by spikey
Welcome!

How can I put this? This code is ... incomplete. We aren't going to be able to help much with incomplete code, but if your actual code looks similar I'm guessing that your crash comes from a stack corruption. Where does "Array()" come from? There are no declarations for it in either sample.

Re: ProcedureCDLL Return Result

Posted: Mon Sep 23, 2024 6:18 pm
by Leo1958
@jacdelad

Thanks for the reply, sorry about no code tags. The Global works within the routine I use.

Here's the full procedure and yes it's to wrap Fmodex v444.64 inside a DLL to get the array of Singles
for a spectrum. This works, see below.

Code: Select all

ProcedureDLL GetSpectrumData()
Global Dim SpectrumLeft.f(512) ;    Fmod Returns Floats
Global Dim SpectrumRight.f(512);    in both channels
Global Dim PeekSpectrum.i(512);    Scale Channel floats added to integer

;function FMOD_System_GetSpectrum(system: FMOD_SYSTEM; var spectrumarray: Single; numvalues: Integer; channeloffset: Integer; windowtype: FMOD_DSP_FFT_WINDOW): FMOD_RESULT; stdcall;

; Do the Left channel First
  CallFunction(FmodLib,"FMOD_System_GetSpectrum",Fmodsystem,SpectrumLeft(),64,0,0)
   ; Do the Right channel Second
  Result=CallFunction(FmodLib,"FMOD_System_GetSpectrum",Fmodsystem,SpectrumRight(),64,1,0)
  ; Peek the channel floats then Average to integer Buffer
  ; All 512 Entries
  For Count=0 To 511 Step 1
    If IntQ(((SpectrumLeft(Count)+SpectrumRight(Count)))*100)>=100 ; Limit the max value
      PeekSpectrum(Count)=50                                       ; Down 
    Else
        PeekSpectrum(Count)=IntQ(((SpectrumLeft(Count)+SpectrumRight(Count)))*200)+1 ; Everything else Amplify!
    EndIf
    ;SpectrumDatum=Round((SpectrumLeft(Count)+SpectrumRight(Count)/2),#PB_Round_Nearest) 
   ;PeekSpectrum(Count)=Int(SpectrumDatum)  
    Next Count
 
 ProcedureReturn Result
EndProcedure
This is the routine to get individual data elements out of the spectrum array of integers

Code: Select all

ProcedureCDLL.i PeekData(D)
R=PeekSpectrum(V) 
Result=R
 ProcedureReturn Result
EndProcedure
This will not work and yet if I set the second line of code to

Code: Select all

R=PeekSpectrum(100) 
It works

@spikey

Thanks for the reply,

So, how would I protect the stack? An old familiar term in the days of the Z80 etc.

Thanks again

Re: ProcedureCDLL Return Result

Posted: Mon Sep 23, 2024 6:44 pm
by spikey

Code: Select all

ProcedureCDLL.i PeekData(D)
R=PeekSpectrum(V) 
Result=R
 ProcedureReturn Result
EndProcedure
In this section you have a parameter D which you aren't using - why? You do use a variable V - but there's no indication of how V is initialised. There doesn't appear to be anything which ensures V is in range. The change you say results in a success has a determinate and in range value. At a guess this is the root of the problem.

Re: ProcedureCDLL Return Result

Posted: Mon Sep 23, 2024 6:54 pm
by Leo1958
Sorry Spikey, it should be

Code: Select all

ProcedureCDLL.i PeekData(V)
R=PeekSpectrum(V) 
Result=R
 ProcedureReturn Result
EndProcedure
V and R are defined at the start of the dll code to be an integer, still the same after the change.
I do intend to look at saving all registers with the inline coder later.

p.s. Back to the days of push and pop!

thanks again
Leo

Re: ProcedureCDLL Return Result

Posted: Mon Sep 23, 2024 7:10 pm
by spikey
Leo1958 wrote: Mon Sep 23, 2024 6:54 pm V and R are defined at the start of the dll code to be an integer, still the same after the change.
Be mindful of scopes. Global V is not equal to Parameter V:

Code: Select all

Global V.i

ProcedureCDLL.i PeekData(V)
  Debug "In procedure: " + V  
EndProcedure

V = 100
Debug "In main before procedure call: " + V

PeekData(200)

Debug "In main after procedure call: " + V

Re: ProcedureCDLL Return Result

Posted: Mon Sep 23, 2024 11:03 pm
by jacdelad
Leo1958 wrote: Mon Sep 23, 2024 6:18 pm The Global works within the routine I use.
Just because it works doesn't mean it's right. :wink:
Take a look at the help, it should clear this up:
Global: https://www.purebasic.com/documentation ... lobal.html
Define: https://www.purebasic.com/documentation ... efine.html
Protected: https://www.purebasic.com/documentation ... ected.html
Static: https://www.purebasic.com/documentation ... tatic.html
Threaded: https://www.purebasic.com/documentation ... eaded.html

Global/Define/Threaded for global declaration, Protected/Static for local one.
Leo1958 wrote: Mon Sep 23, 2024 6:54 pm V and R are defined at the start of the dll code to be an integer, still the same after the change.
Then please give use the full code!

Re: ProcedureCDLL Return Result

Posted: Tue Sep 24, 2024 11:44 am
by Leo1958
Morning Jacdelad. Sorry here you go.

please note the PeekSpectrumData_0 routines at the bottom go all the way upto
PeekSpectrum_Data_63, too much to post.

Crude I know, only to see if it worked in getting the Spectrum data

Anyway, Thanks for looking at it, Appreciate it.

Cheers!


Code: Select all

Global FmodSystem.i,Sound.i,Channel.i,file.s,PauseStatus.i,PlayStatus.b,Flag.b,Mode.i
Global Result.i,Count.i

PrototypeC _GetAGKFunction(Function.p-ascii)
 
ProcedureCDLL ReceiveAGKPtr(*GetFunction)
 
 GetAGKFunction._GetAGKFunction=*GetFunction
 
EndProcedure

  
ProcedureDLL Init()
    Global FmodLib=OpenLibrary(#PB_Any,"Fmodex64.dll")
    ProcedureReturn FmodLib  
 EndProcedure

ProcedureDLL Play(File)
   Result=CallFunction(FmodLib,"FMOD_System_Create",@Fmodsystem)
   Result1=CallFunction(FmodLib,"FMOD_System_Init",Fmodsystem,32,0,0)  ;FMOD_INIT_NORMAL
   Result2=CallFunction(FmodLib,"FMOD_System_CreateStream",Fmodsystem,File,64|2,0,@Sound)
   Result3=CallFunction(FmodLib,"FMOD_System_PlaySound",Fmodsystem,0,Sound,0,@Channel)
   Global flag=1
   ProcedureReturn flag
 EndProcedure

ProcedureDLL Stop()
  Result=CallFunction(FmodLib,"FMOD_Channel_Stop",Channel)
  ;Global flag=0
  ;ProcedureReturn Result
EndProcedure

ProcedureDLL Close()
   Result=CallFunction(FmodLib,"FMOD_System_Release",Fmodsystem)
   CloseLibrary(FmodLib)
 EndProcedure
 
ProcedureDLL IsPlaying()
   CallFunction(FmodLib,"FMOD_Channel_IsPlaying",Channel,@PlayStatus)
   If Playstatus=#False
     Result=0
        Else
     Result=1
        EndIf
   ProcedureReturn Result     
 EndProcedure
 
ProcedureDLL Pause()
    ;Get channel pause status
  CallFunction(FmodLib,"FMOD_Channel_GetPaused",Channel, @PauseStatus) 
    If PauseStatus = #False
      CallFunction(FmodLib,"FMOD_Channel_SetPaused",Channel, #True) ;Pause
      result=1
      Else
  CallFunction(FmodLib,"FMOD_Channel_SetPaused",Channel, #False) ;Play
      Result=0  
   EndIf
  ProcedureReturn Result  
EndProcedure  

ProcedureDLL GetSpectrumData()

Global Dim SpectrumLeft.f(512)     ;           Fmod Returns Floats
Global Dim SpectrumRight.f(512)    ;             in both channels
Global Dim PeekSpectrum.i(512)     ;    Scale Channel floats convert to integer

; Do the Left channel First
  CallFunction(FmodLib,"FMOD_System_GetSpectrum",Fmodsystem,SpectrumLeft(),511,0,0)
   ; Do the Right channel Second
  Result=CallFunction(FmodLib,"FMOD_System_GetSpectrum",Fmodsystem,SpectrumRight(),511,1,0)
  ; Peek the channel floats then Average to integer Buffer
  ; All 512 Entries
  For Count=0 To 511 Step 1
    If IntQ(((SpectrumLeft(Count)+SpectrumRight(Count)))*100)>=100 ; Limit the max value
      PeekSpectrum(Count)=50                                       ; Down 
    Else
        PeekSpectrum(Count)=IntQ(((SpectrumLeft(Count)+SpectrumRight(Count)))*200)+1 ; Everything else Amplify!
  EndIf
    Next Count

 ProcedureReturn Result
EndProcedure

ProcedureDLL.i PeekSpectrumData()
  Result=PeekSpectrum(0)
  ProcedureReturn Result
EndProcedure

ProcedureDLL.i PeekSpectrumData_1()
  Result=PeekSpectrum(1)
  ProcedureReturn Result
EndProcedure

ProcedureDLL.i PeekSpectrumData_2()
  Result=PeekSpectrum(2)
  ProcedureReturn Result
EndProcedure

ProcedureDLL.i PeekSpectrumData_3()
  Result=PeekSpectrum(3)
  ProcedureReturn Result
EndProcedure  


Re: ProcedureCDLL Return Result

Posted: Tue Sep 24, 2024 2:11 pm
by jacdelad
Ok, I must confess I find this code a bit weird. The PeekSpectrumData_x() functions could use a parameter, so you would only need one function instead of 4 (or more).
You absolutely should use EnableExplicit, or I bet you will get problems with your variables later!
Now, show us the complete calling program (or as much code as is needed to get it running). It's hard to understand what happens until your error occurs.
Also: Why use a DLL for the DLL? Is the calling program Non-PB?

Re: ProcedureCDLL Return Result

Posted: Tue Sep 24, 2024 3:04 pm
by Leo1958
Yes, it’s used in an external program wrote with
AGK Studio. It’s a plugin to that program and yes
The routine would far easier to pass a variable to it inside
A loop.

Out at the moment will look at you suggestion later
When home.

Cheers

Leo

Ps Oscilloscope data working with similar multiple
Routines to get the wave shape.