• Welcome to Powerbasic Museum 2020-B.
 

News:

Forum in repository mode. No new members allowed.

Main Menu

Wrong return values from third-party dll

Started by Olav Bergesen, November 27, 2012, 06:32:47 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Olav Bergesen

Hello!

The Code below is a FreeBasic routine which produce and returns correct values when run as an EXE, but when the code is
compiled to a DLL file and called from PB, it returns totally different and wrong values(See below).

In PB:
Declare Function FirstBitt Alias "FirstBitt" (Quad)Import "FindFirstBit.dll" As Long
  ? firstBitt(65280)
  ? firstBitt(16842752)
  ? firstbitt(16777216)
  ? firstbitt(65024)
  ? firstbitt(33685504)
  ? firstbitt(64512)

Anyone any idea?
--
Olav


Function FirstBitt CDecl Alias "FirstBitt" (Bittmap As LongInt) As Long Export
'Function FirstBitt (Bittmap As LongInt) As Long ' run as an exe
  If Bittmap = 0 Then Exit Function

    ' De Bruijn Multiplication, see http:'chessprogramming.wikispaces.com/BitScan
    ' don't use this if bitmap = 0

  Dim INDEX64(63) As Long

  INDEX64(0) = 63
  INDEX64(1) = 0
  INDEX64(2) = 58
  INDEX64(3) =  1
  INDEX64(4) = 59
  INDEX64(5) =  47
  INDEX64(6) = 53
  INDEX64(7) =  2
  INDEX64(8) = 60
  INDEX64(9) = 39
  INDEX64(10) = 48
  INDEX64(11) = 27
  INDEX64(12) = 54
  INDEX64(13) = 33
  INDEX64(14) = 42
  INDEX64(15) =  3
  INDEX64(16) = 61
  INDEX64(17) = 51
  INDEX64(18) = 37
  INDEX64(19) = 40
  INDEX64(20) =  49
  INDEX64(21) = 18
  INDEX64(22) = 28
  INDEX64(23) = 20
  INDEX64(24) = 55
  INDEX64(25) = 30
  INDEX64(26) = 34
  INDEX64(27) = 11
  INDEX64(28) = 43
  INDEX64(29) = 14
  INDEX64(30) = 22
  INDEX64(31) =  4
  INDEX64(32) =  62
  INDEX64(33) = 57
  INDEX64(34) = 46
  INDEX64(35) = 52
  INDEX64(36) = 38
  INDEX64(37) = 26
  INDEX64(38) =  32
  INDEX64(39) =  41
  INDEX64(40) =  50
  INDEX64(41) = 36
  INDEX64(42) = 17
  INDEX64(43) = 19
  INDEX64(44) = 29
  INDEX64(45) = 10
  INDEX64(46) = 13
  INDEX64(47) = 21
  INDEX64(48) = 56
  INDEX64(49) = 45
  INDEX64(50) = 25
  INDEX64(51) = 31
  INDEX64(52) = 35
  INDEX64(53) = 16
  INDEX64(54) =  9
  INDEX64(55) =  12
  INDEX64(56) =  44
  INDEX64(57) =  24
  INDEX64(58) =  15
  INDEX64(59) =  8
  INDEX64(60) = 23
  INDEX64(61) =  7
  INDEX64(62) =  6
  INDEX64(63) =  5

'65280     bittmap 17137856407927308800  unsigned __int64
'16842752      bittmap 15412894960227319808  unsigned __int64
'16777216     bittmap 16544622118059376640  unsigned __int64
' 65024     bittmap 15828968742145065984  unsigned __int64
'33685504     bittmap 12379045846745088000  unsigned __int64
'64512     bittmap 13211193410580580352  unsigned __int64

  Dim  DEBRUIJN64 As ULongint
  Dim BB As ULongInt
  DEBRUIJN64 = &H07EDD5E59A4E28C2
  BB = (Bittmap And -Bittmap) * DEBRUIJN64
  BB = BB Shr 58
  Function = INDEX64(BB)

End Function

' Run as an exe
                            '  Returns as non-dll(Same as in C) ' Called from PB it returns
'Print firstbitt(65280)     '    8                                            3
'Print firstbitt(16842752)  '   16                                            2
'Print firstbitt(16777216)  '   24                                            5
'Print firstbitt(65024)     '    9                                            2
'Print firstbitt(33685504)  '   17                                            3
'Print firstbitt(64512)     '   10                                            2
'Sleep
'End

José Roca

You are using the CDECL calling convention in the FreeBasic function, but STDCALL in the PB declare.

Use:


Declare Function FirstBitt CDECL  Import "FindFirstBit.dll" Alias "FirstBitt" (Bittmap As QUAD) As Long


Olav Bergesen

Quote from: José Roca on November 27, 2012, 06:50:59 PM
You are using the CDECL calling convention in the FreeBasic function, but STDCALL in the PB declare.

Use:


Declare Function FirstBitt CDECL  Import "FindFirstBit.dll" Alias "FirstBitt" (Bittmap As QUAD) As Long


Thanks for quick reply, but I'm sorry to say that CDECL didn't work. With this keyword added, the DLL routine returned the value 3 for all of the different input values, shown in the original message.
--
Olav

José Roca

Probably it is because quads are signed integers and in your FreeBasic code you are using it as if it was unsigned.

Olav Bergesen

Quote from: José Roca on November 27, 2012, 07:41:33 PM
Probably it is because quads are signed integers and in your FreeBasic code you are using it as if it was unsigned.

I have made some changes, but it still returns 3 for all different input values.
I can't quite understand that those unsigned 64 bit variables, local to the function, should affect the function's return
value. Or am I wrong on this?
--

In FreeBasic:
Function FirstBitt CDecl Alias "FirstBitt" (Bittmap As LongInt) As LongInt Export
'LongInt is the same as QUAD in PB
....
....
Function = CLngInt(INDEX64(BB))

In PB:
Declare Function FirstBitt  Alias "FirstBitt" (Bittmap As Quad)CDecl, Import "FindFirstBit.dll" As Quad

A bit suprising that PB does not have native support for unsigned 64 bit variables.
--
Olav

José Roca

Try using an ULARGE_INTEGER structure in your PB declaration:

TYPE ULARGE_INTEGER
   LowPart  AS DWORD
   HighPart AS DWORD
END TYPE

Olav Bergesen

Quote from: José Roca on November 27, 2012, 09:24:20 PM
Try using an ULARGE_INTEGER structure in your PB declaration:

TYPE ULARGE_INTEGER
   LowPart  AS DWORD
   HighPart AS DWORD
END TYPE

Thanks for your suggestion, but I have solved the problem. Just learned that FreeBasic pass parameters BYVAL as
default. So all I had to do was to add a BYVAL to the parameter in the DECLARE statement.

Declare Function FirstBitt  Alias "FirstBitt" (ByVal Bittmap As Quad) Import "FindFirstBit.dll" As Quad

Didn't need the CDECL either.

Thanks for your time!
--
Olav

José Roca

I wonder why they call these compilers BASIC, if they don't follow the rules of the BASIC language.

> Didn't need the CDECL either.

If you FrreeBASIC function uses the CDECL calling convention, you need it; otherwise, the stack won't be cleaned. You must use the same calling convention in the two languages.


Olav Bergesen

Quote from: José Roca on November 28, 2012, 08:29:22 AM
I wonder why they call these compilers BASIC, if they don't follow the rules of the BASIC language.

> Didn't need the CDECL either.

If you FrreeBASIC function uses the CDECL calling convention, you need it; otherwise, the stack won't be cleaned. You must use the same calling convention in the two languages.

Thanks for that information.

BYVAL:
I wouldn't mind if Powerbasic came up with something like #OPTION BYVAL ON, whatever. Think of how much typing one could save(shorter line too), and in addition BYVAL as default would comply with/to the principle that one should use local variables over global ones. BYREF variables is in a way a kind of globals , in my opionion.
--
Olav