Problem using PB64 with 3rd Party 64-bit App

Just starting out? Need help? Post your questions and find answers here.
TeraByte
User
User
Posts: 40
Joined: Wed May 09, 2012 12:40 am

Problem using PB64 with 3rd Party 64-bit App

Post by TeraByte »

I wrote the following simple 64 bit DLL and am unable to get it to work with a 3rd party application called Multicharts64. The problem seems to be when I try to return a double or float. I'm using PB64 v4.61.

Code: Select all

EnableExplicit

; These 4 procedures are Windows specific
;

; This procedure is called once, when the program loads the library
; for the first time. All init stuffs can be done here (but not DirectX init)
;
ProcedureDLL AttachProcess(Instance)
EndProcedure


; Called when the program release (free) the DLL
;
ProcedureDLL DetachProcess(Instance)
EndProcedure

; Both are called when a thread in a program call or release (free) the DLL
;
ProcedureDLL AttachThread(Instance)
EndProcedure

ProcedureDLL DetachThread(Instance)
EndProcedure

;
; Real code start here..
;

ProcedureDLL.l AddLong(num1.l, num2.l)
  Protected Mysum.l
  Mysum = num1 + num2
  ProcedureReturn Mysum
EndProcedure

ProcedureDLL.f AddFloat(num1.f, num2.f)
  Protected Mysum.f  
  Mysum = num1 + num2
  ProcedureReturn Mysum
EndProcedure

ProcedureDLL.d AddDouble(num1.d, num2.d)
  Protected Mysum.d
  Mysum = num1 + num2
  ProcedureReturn Mysum
EndProcedure

ProcedureDLL.i AddInt(num1.i, num2.i)
  Protected Mysum.i
  Mysum = num1 + num2
  ProcedureReturn Mysum
EndProcedure

ProcedureDLL Mult2xRefFloat(*num1.Float, *num2.Float)
  *num1\f = (*num1\f) * 2.0
  *num2\f = (*num2\f) * 2.0
EndProcedure

ProcedureDLL Mult2xRefDouble(*num1.Double, *num2.Double)
  *num1\d = (*num1\d) * 2.0
  *num2\d = (*num2\d) * 2.0
EndProcedure

The following procedures work fine: AddLong, AddInt, Mult2xRefFloat and Mult2xRefDouble.

PROBLEM:
The following procedures FAIL: AddFloat, and AddDouble

AddFloat(3.14, 2.15) returns: 3.14 rather than 5.29
AddDouble(4.14, 5.15) returns: 4.14 rather than 9.29

The 3rd Party app Multicharts support staff say the problem is something in my PB DLL64.

I would really appreciate your experts insight. Have I done something wrong in the PB code? Thank you.
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Problem using PB64 with 3rd Party 64-bit App

Post by srod »

My guess would be that the 3rd party app is not expecting that floating point returns are placed on the floating point stack (which is where PB leaves them).

I've seen something like this before.

Try the following :

Code: Select all

ProcedureDLL.l AddFloat(num1.f, num2.f)
  Protected Mysum.f  
  Mysum = num1 + num2
  ProcedureReturn PeekL(@Mysum)
EndProcedure
I may look like a mule, but I'm not a complete ass.
TeraByte
User
User
Posts: 40
Joined: Wed May 09, 2012 12:40 am

Re: Problem using PB64 with 3rd Party 64-bit App

Post by TeraByte »

Thanks srod for the suggestion. Unfortunately, it did not work. Here's the snippet of modified code. I put in your changes and also output some info to a log file:

Code: Select all

ProcedureDLL.f AddFloat(num1.f, num2.f)
  Protected Mysum.f  
  Mysum = num1 + num2
  CompilerIf #DebugLog=1
    PrintToFile("v20120609-1417 AddFloat:" + StrF(Num1) + " + " + StrF(Num2) + " = " + StrF(mysum) + ", PeekL=" + Str(PeekL(@MySum)))
  CompilerEndIf

  ProcedureReturn PeekL(@Mysum)
EndProcedure

ProcedureDLL.d AddDouble(num1.d, num2.d)
  Protected Mysum.d
  Mysum = num1 + num2
  CompilerIf #DebugLog=1
    PrintToFile("AddDouble:" + StrD(Num1) + " + " + StrD(Num2) + " = " + StrD(mysum) + ", PeekL=" + Str(PeekL(@MySum)))
  CompilerEndIf

  ProcedureReturn PeekL(@Mysum)
EndProcedure
Here's the output file:

v20120609-1417 AddFloat:3.1400001049 + 2.1500000954 = 5.2899999619, PeekL=1084835758
14:19:26:: AddDouble:4.1400000000 + 5.1500000000 = NaN, PeekL=0

So the AddFloat is computing the correct sum, but the 3rd party app is returning a zero.

The AddDouble is receiving the correct numbers to add, but the sum is NaN.

This doesn't make sense. I hope some expert can figure out this oddity.
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Problem using PB64 with 3rd Party 64-bit App

Post by srod »

You haven't copied my code correctly.

Code: Select all

ProcedureDLL.l AddFloat(num1.f, num2.f)
  Protected Mysum.f  
  Mysum = num1 + num2
  ProcedureReturn PeekL(@Mysum)
EndProcedure
ProcedureDLL.l not .f !!!
I may look like a mule, but I'm not a complete ass.
TeraByte
User
User
Posts: 40
Joined: Wed May 09, 2012 12:40 am

Re: Problem using PB64 with 3rd Party 64-bit App

Post by TeraByte »

Hi srod, thanks for your correction. Now I have it exactly like yours. The output from 3rd party app is "0". Here is the output from the log file:

2012-06-09, 16:27:59:: v20120609-1424 AddFloat:3.1400001049 + 2.1500000954 = 5.2899999619, PeekL=1084835758

Code: Select all


EnableExplicit

#DebugLog = 1               ; Off=0,  On=1
Procedure PrintToFile( MyOut.s)
  Define Tempstr.s
  Define FileNum.l
  
    FileNum = OpenFile (#PB_Any,"c:\IEC_Log.txt")
    If FileNum > 0 
      FileSeek(FileNum, Lof(FileNum))    
      Tempstr=  FormatDate("%yyyy-%mm-%dd, %hh:%ii:%ss:", Date() ) + ": " + MyOut
      WriteStringN(FileNum, Tempstr)
      CloseFile(FileNum)
    EndIf
    
    CompilerIf #DebugLog
        OutputDebugString_("PrintToFile: " + Tempstr)
    CompilerEndIf
EndProcedure
;
; These 4 procedures are Windows specific
;
; This procedure is called once, when the program loads the library
; for the first time. All init stuffs can be done here (but not DirectX init)
;
ProcedureDLL AttachProcess(Instance)
EndProcedure

; Called when the program release (free) the DLL
;
ProcedureDLL DetachProcess(Instance)
EndProcedure

; Both are called when a thread in a program call or release (free) the DLL
;
ProcedureDLL AttachThread(Instance)
EndProcedure

ProcedureDLL DetachThread(Instance)
EndProcedure

;
; Real code start here..
;
ProcedureDLL.l AddLong(num1.l, num2.l)
  Protected Mysum.l
  Mysum = num1 + num2
  ProcedureReturn Mysum
EndProcedure

ProcedureDLL.l AddFloat(num1.f, num2.f)
  Protected Mysum.f  
  Mysum = num1 + num2
  CompilerIf #DebugLog=1
    PrintToFile("v20120609-1424 AddFloat:" + StrF(Num1) + " + " + StrF(Num2) + " = " + StrF(mysum) + ", PeekL=" + Str(PeekL(@MySum)))
  CompilerEndIf
  ProcedureReturn PeekL(@Mysum)
EndProcedure

ProcedureDLL.d AddDouble(num1.d, num2.d)
  Protected Mysum.d
  Mysum = num1 + num2
  ProcedureReturn Mysum
EndProcedure

ProcedureDLL.i AddInt(num1.i, num2.i)
  Protected Mysum.i
  Mysum = num1 + num2
  ProcedureReturn Mysum
EndProcedure

ProcedureDLL Mult2xRefFloat(*num1.Float, *num2.Float)
  *num1\f = (*num1\f) * 2.0
  *num2\f = (*num2\f) * 2.0
EndProcedure

ProcedureDLL Mult2xRefDouble(*num1.Double, *num2.Double)
  *num1\d = (*num1\d) * 2.0
  *num2\d = (*num2\d) * 2.0
EndProcedure
TeraByte
User
User
Posts: 40
Joined: Wed May 09, 2012 12:40 am

Re: Problem using PB64 with 3rd Party 64-bit App

Post by TeraByte »

As another quick test, I tried the following code which returns "112596307.00"

Code: Select all

ProcedureDLL.d ReturnDouble()
  ProcedureReturn 7.123
EndProcedure
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Problem using PB64 with 3rd Party 64-bit App

Post by srod »

Ok, I still think that the problem is that the float is being returned in a way which the 3rd party app is not expecting. Perhaps, the return is expected to be placed in one of the registers such as RDX as opposed to the top of the fp stack?

What does the documentation say regarding the use of your dll? Is it perhaps expecting a pointer return instead?
I may look like a mule, but I'm not a complete ass.
Helle
Enthusiast
Enthusiast
Posts: 178
Joined: Wed Apr 12, 2006 7:59 pm
Location: Germany
Contact:

Re: Problem using PB64 with 3rd Party 64-bit App

Post by Helle »

The 3rd party app expect the result in register xmm0 (standard for 64-bit float/double-procedures).
Try this:

Code: Select all

;For Test
TestFloat.f
TestDouble.d

ProcedureDLL.f AddFloat(num1.f, num2.f)     ;num1=XMM0, num2=XMM1
  Shared MysumF.f       ;!
  MysumF = num1 + num2
 !MOVSS XMM0,[v_MysumF]
EndProcedure

;or simple
ProcedureDLL.f AddFloat3rdparty(num1.f, num2.f)  ;num1=XMM0, num2=XMM1
  !ADDSS XMM0,XMM1
EndProcedure

ProcedureDLL.d AddDouble(num1.d, num2.d)     ;num1=XMM0, num2=XMM1
  Shared MysumD.d       ;!
  MysumD = num1 + num2
 !MOVSD XMM0,[v_MysumD]
EndProcedure

;or simple
ProcedureDLL.d AddDouble3rdparty(num1.d, num2.d) ;num1=XMM0, num2=XMM1
  !ADDSD XMM0,XMM1
EndProcedure

;Test
AddFloat(3.14, 2.15)
!MOVSS [v_TestFloat],XMM0
Debug TestFloat

AddFloat3rdparty(3.14, 2.15)
!MOVSS [v_TestFloat],XMM0
Debug TestFloat

AddDouble(4.14, 5.15)
!MOVSD [v_TestDouble],XMM0
Debug TestDouble

AddDouble3rdparty(4.14, 5.15)
!MOVSD [v_TestDouble],XMM0
Debug TestDouble

Note: Debug destroy register XMM0 (if you make tests)!
Have fun!
Helle
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Problem using PB64 with 3rd Party 64-bit App

Post by srod »

Ah, I don't know enough about x64 asm code, but at least we were on the right track; the only possible explanation really. :)

Let's hope that does the trick.
I may look like a mule, but I'm not a complete ass.
c4s
Addict
Addict
Posts: 1981
Joined: Thu Nov 01, 2007 5:37 pm
Location: Germany

Re: Problem using PB64 with 3rd Party 64-bit App

Post by c4s »

...Isn't it a bug then?
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
DarkDragon
Addict
Addict
Posts: 2344
Joined: Mon Jun 02, 2003 9:16 am
Location: Germany
Contact:

Re: Problem using PB64 with 3rd Party 64-bit App

Post by DarkDragon »

c4s wrote:...Isn't it a bug then?
No, compatibility to other languages was never a big official feature of purebasic.
bye,
Daniel
xorc1zt
Enthusiast
Enthusiast
Posts: 276
Joined: Sat Jul 09, 2011 7:57 am

Re: Problem using PB64 with 3rd Party 64-bit App

Post by xorc1zt »

the code

Code: Select all

ProcedureDLL.f Return_float()
    ProcedureReturn 8.55
EndProcedure

ProcedureDLL.d Return_double()
    ProcedureReturn 8.55
EndProcedure
produce

Code: Select all

.code:0000000180001084 ; Exported entry   1. Return_double
.code:0000000180001084
.code:0000000180001084 ; =============== S U B R O U T I N E =======================================
.code:0000000180001084
.code:0000000180001084
.code:0000000180001084                 public Return_double
.code:0000000180001084 Return_double   proc near               
.code:0000000180001084                 sub     rsp, 28h
.code:0000000180001088                 fld     cs:dbl_180004014			; 8.550000000000001
.code:000000018000108E                 jmp     short loc_180001092
.code:0000000180001090                 fldz
.code:0000000180001092 loc_180001092:
.code:0000000180001092                 add     rsp, 28h
.code:0000000180001096                 retn
.code:0000000180001096 Return_double   endp
.code:0000000180001096


.code:0000000180001097 ; Exported entry   2. Return_float
.code:0000000180001097
.code:0000000180001097 ; =============== S U B R O U T I N E =======================================
.code:0000000180001097
.code:0000000180001097
.code:0000000180001097                 public Return_float
.code:0000000180001097 Return_float    proc near          
.code:0000000180001097                 sub     rsp, 28h
.code:000000018000109B                 fld     cs:flt_180004010			; 8.5500002
.code:00000001800010A1                 movsxd  rax, eax
.code:00000001800010A4                 jmp     short loc_1800010A8
.code:00000001800010A6                 fldz
.code:00000001800010A8 loc_1800010A8: 
.code:00000001800010A8                 add     rsp, 28h
.code:00000001800010AC                 retn
.code:00000001800010AC Return_float    endp
.code:00000001800010AC
why fldz ?
Post Reply