Oxygen Basic

Programming => Bugs & Feature Requests => Topic started by: efgee on January 10, 2011, 02:24:15 PM

Title: Using a O2 DLL with apps generated with other compilers
Post by: efgee on January 10, 2011, 02:24:15 PM
Hello,
trying to use a DLL created with OxygenBasic in conjunction with programs programmed in other programming languages.
The only thing I use are normal functions like:
(independent or with oxygen.dll doesn't matter...)

Code: [Select]
 $ dll
  $ FileName dll_math_o2
  includepath "..\inc\"
  include "RTL32.inc"

function IsInitialized() as long export
function = (1)
end function

function MathAdd(N1 as long, N2 as long) as long export
function = (N1 + N2)
end function

function MathDiv(N1 as long, N2 as long) as long export
function = (N1 / N2)
end function

function MathMul(N1 as long, N2 as long) as long export
function = (N1 * N2)
end function

function MathSub(N1 as long, N2 as long) as long export
function = (N1 - N2)
end function

The first one I tried was a Purebasic program and it seems that dynamic loading of an OxygenBasic DLL does not work; DLLs created with other compilers work well though.

Has anyone had more luck?

Thanks
efgee
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: Charles Pegge on January 10, 2011, 03:22:47 PM
Hi efgee,

It looks okay from here.
Was PureBasic able to load the DLL? LoadLibrary is a direct call to the Kernel.

Charles

Anywhere PE Viewer 0.17
Code: [Select]
C:\cevp\projects\opcode\OxygenBasic\Examples\UseRTL32\dll_math_o2.dll
Export table
Characteristics=0, TimeDateStamp=1294783729, MajorVersion=0, MinorVersion=0, Name=45104, Base=1, NumberOfFunctions=5, NumberOfNames=5, AddressOfFunctions=45124, AddressOfNames=45160, AddressOfNameOrdinals=45148,
TimeDateStamp:Tue Jan 11 22:08:49 GMT 2011
IsInitialized (Ordinal: 1, Entry Point RVA: 3440h (13,376))
MathAdd (Ordinal: 2, Entry Point RVA: 3470h (13,424))
MathDiv (Ordinal: 3, Entry Point RVA: 34b0h (13,488))
MathMul (Ordinal: 4, Entry Point RVA: 34f0h (13,552))
MathSub (Ordinal: 5, Entry Point RVA: 3530h (13,616))
Generated with Anywhere PE Viewer/APEVPX (http://www.ucware.com/)

Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: Charles Pegge on January 10, 2011, 03:39:35 PM

Program to test the DLL including header (Oxygen)

Code: [Select]

'  $ dll
'  $ FileName dll_math_o2
'  includepath "..\..\inc\"
'  include "RTL32.inc"

'NB automatic case sensitivity so you dont need to use ALIAS clauses in the extern block

extern lib "dll_math_o2.dll"

declare function IsInitialized() as long
declare function MathAdd(N1 as long, N2 as long) as long
declare function MathDiv(N1 as long, N2 as long) as long
declare function MathMul(N1 as long, N2 as long) as long
declare function MathSub(N1 as long, N2 as long) as long

end extern


print IsInitialized

print MathMul 3,4
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: efgee on January 10, 2011, 04:54:45 PM
Hi efgee,
It looks okay from here.
Was PureBasic able to load the DLL? LoadLibrary is a direct call to the Kernel.

Yes the DLL was loaded and the "LibraryAddress" function gives the following address for the functions:

IsInitialized : $10003440
MathAdd : $10003470
MathDiv : $100034B0
MathMul : $100034F0
MathSub : $10003530

I suppose these addresses differ by $10000000 because the OS tries to map/relocate the functions.

One thing I don't understand is that a DLL normally has ".reloc" section but a Oxygen generated DLL has not...
(afaik the functions need to be relocateable...)

bye
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: Charles Pegge on January 10, 2011, 10:03:47 PM
efgee,

Does PureBasic default to param passing byRef or ByVal? - just thinking about other sources of error.

The location should not matter. All Oxygen code is relocatable and does not require reloc sections to adjust absolute addresses.

I found that loading the dll in Oxygen (under Vista) gave the different locations almost every time.

print hex & IsInitialized

1F3440
203440
1D3440
1B3440
233440


Here is the DLL being used by thinBasic

Code: [Select]

declare function IsInitialized lib "dll_math_o2.dll" alias "IsInitialized" () as long
declare function MathAdd lib "dll_math_o2.dll" alias "MathAdd" (N1 as long, N2 as long) as long
declare function MathDiv lib "dll_math_o2.dll" alias "MathDiv" (N1 as long, N2 as long) as long
declare function MathMul lib "dll_math_o2.dll" alias "MathMul" (N1 as long, N2 as long) as long
declare function MathSub lib "dll_math_o2.dll" alias "MathSub" (N1 as long, N2 as long) as long

dim as long a,b
a=3 : b=4

msgbox 0,IsInitialized
msgbox 0,MathMul(a,b)


and with PowerBasic

Code: [Select]
'PowerBasic
$COMPILE EXE

DECLARE FUNCTION IsInitialized LIB "dll_math_o2.dll" ALIAS "IsInitialized" () AS LONG
DECLARE FUNCTION MathAdd LIB "dll_math_o2.dll" ALIAS "MathAdd" (N1 AS LONG, N2 AS LONG) AS LONG
DECLARE FUNCTION MathDiv LIB "dll_math_o2.dll" ALIAS "MathDiv" (N1 AS LONG, N2 AS LONG) AS LONG
DECLARE FUNCTION MathMul LIB "dll_math_o2.dll" ALIAS "MathMul" (N1 AS LONG, N2 AS LONG) AS LONG
DECLARE FUNCTION MathSub LIB "dll_math_o2.dll" ALIAS "MathSub" (N1 AS LONG, N2 AS LONG) AS LONG

FUNCTION PBMAIN()

DIM a AS LONG,b AS LONG
a=3 : b=4

MSGBOX STR$(IsInitialized)
MSGBOX STR$(MathMul(a,b))

END FUNCTION

Charles
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: efgee on January 11, 2011, 06:27:58 AM
I think PureBasic uses byVal...  :-\

Do the "Declare Function" declarations in Oxygen, thinBasic and PowerBasic use "LoadLibrary"?
(so called late binding)
I assumed what they do is early binding...

With PureBasic I could also test early binding, but I have to find a program that generates a working static import library off the DLL.

Thanks
efgee
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: jack on January 11, 2011, 08:34:01 AM
... but I have to find a program that generates a working static import library off the DLL.
since you have PureBasic you already have it, it's Polib.
you can either add C:\Program Files\PureBasic\Compilers to the path variable or copy your dll to Compilers folder
and then type the following command: polib yourdll.dll /machine:x86 /out:yourdll.lib
BTW, I use the LibDump utility found here http://www.gpoulose.com/ to view the lib exported functions, I know there's dependency walker
but for simple name dump prefer LibDump.
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: Charles Pegge on January 11, 2011, 09:49:49 AM

I would try specifying "byref" in the declarations - if it has already given you valid procaddresses then this is the usual problem.

Oxygen actually uses GetProcAddress for most of its binding. Only its bootstrap uses true early binding. - by which I mean having tables in the import section of the PE file that are initialised by the Operating system at load time.

In Oxygen all declarations associated with a library (& only those which are called in the program) are bunched together at the top of the code so they are resolved in one go before the rest of the program is executed. However there are several ways to late bind. A declared function may be assigned or reassigned a ProcAddress at any time.

Example:
Code: [Select]
declare function foo(byref a as long) as long
'...
& foo = GetProcAddress(BahLib,"foo")
if not & foo then
  print "sorry! can't locate function foo in BahLib" : '...
else
  print foo(42)
end if

Charles
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: efgee on January 11, 2011, 11:19:20 AM
... but I have to find a program that generates a working static import library off the DLL.
since you have PureBasic you already have it, it's Polib.
you can either add C:\Program Files\PureBasic\Compilers to the path variable or copy your dll to Compilers folder
and then type the following command: polib yourdll.dll /machine:x86 /out:yourdll.lib
BTW, I use the LibDump utility found here http://www.gpoulose.com/ to view the lib exported functions, I know there's dependency walker
but for simple name dump prefer LibDump.

Ups, didn't think of that... thank you.

Ok, generated the static lib and wrote this in order to test it (PureBasic):
Code: [Select]
Import "g:\Bunion\examples\dll_math_o2.lib"
  IsInitialized()
  MathMul(n1.i, n2.i)
  MathDiv(n1.i, n2.i)
  MathAdd(n1.i, n2.i)
  MathSub(n1.i, n2.i)
EndImport

Debug IsInitialized()
Debug MathMul(4,2)
Debug MathDiv(4,2)
Debug MathAdd(4,2)
Debug MathSub(4,2)

The first function "IsInitialized" returns a 1 but the program crashes on the second function.
The debugger's error message is: Invalid memory access, (read error at address 4).

The address corresponds with the value of the first parameter - if I change the parameter to 6 the address becomes 6.

Strange...

EDIT
BTW: it's the same error as when the DLL is used with LoadLibrary (PureBasic command is OpenLibrary)
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: efgee on January 11, 2011, 12:05:22 PM
...
The location should not matter. All Oxygen code is relocatable and does not require reloc sections to adjust absolute addresses.

How is this achieved?

That's the first time I hear that a DLL does not need a reloc section  :o
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: Charles Pegge on January 11, 2011, 12:39:36 PM
How do you express 'byref' in the declaration? It needs to pass addresses not values.

Charles
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: jack on January 11, 2011, 12:43:21 PM
efgee, I suggest you try ImportC and see if that works, Purebasic default calling convention is stdcall.
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: efgee on January 11, 2011, 01:04:10 PM
efgee, I suggest you try ImportC and see if that works, Purebasic default calling convention is stdcall.

ImportC results in "one big fat crash".
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: Charles Pegge on January 11, 2011, 01:05:28 PM
Relocatability is achieved by avoiding absolute addresses completely. Addresses are referenced either relatively (for direct jumps and calls) or by offset from a register. EBX contains the absolute address of the .bssdata - the start of the uninitialised data section. All function tables and static variables are mapped out as an offset from this base.

How does register EBX obtain an absolute address to .bssdata at runtime? In 32 bit mode its a little awkward but this is what I do:
Code: [Select]
call fwd here
.here
pop ebx 'get the absolute address of here
sub ebx,here 'deduct virtual address of here
add ebx,bssdata 'add virtual address of bssdata

In 64 bit mode it's so much simpler:
Code: [Select]
lea rip rbx,bssdata 'load effective address (Relative to Instruction Pointer) .bssdata
(The notation will differ in other assemblers)


Charles

Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: efgee on January 11, 2011, 01:06:07 PM
How do you express 'byref' in the declaration? It needs to pass addresses not values.

Charles
Well it is my understanding that doing an "Import" the parameter passing is always done byRef...
I could be wrong though.
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: Charles Pegge on January 11, 2011, 01:14:09 PM
Try putting an asterisk to the left of each param :)

forum ref:
http://forum.purebasic.com/english/viewtopic.php?f=13&t=41893
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: Peter on January 11, 2011, 01:22:46 PM
Hi Charles,

making of Dll's is great!
good work!

here is a Demo
Code: [Select]
indexbase 0
include "win_c.inc"
include "win_g.inc"

Declare Function DrawCircle  Lib "Draws.dll" (byval hdc as long, byval x as long, byval y as long, byval r as long, byval color as long)
Declare Function DrawBox     Lib "Draws.dll" (byval hdc as long, byval x1 as long,byval y1 as long,byval x2 as long,byval y2 as long,byval color as long)
Declare Function DrawEllipse Lib "Draws.dll" (byval hdc as long, byval mx as long,byval my as long,byval r1 as long,byval r2 as long,byval color as long)
Declare Function DrawLine    Lib "Draws.dll" (byval hdc as long, byval x2 as long,byval y2 as long,byval x3 as long,byval y3 as long,byval color as long)

Dim hdc as long
SetWindow "Dll-Demo / OxygenBasic Version o26",800,600,ws_overlapped
hdc = setbuffer winwidth,winheight

while winexit =0
ClearBuffer
DrawCircle  hdc,50,50,40,&HB0B0B0
DrawCircle  hdc,740,50,40,&HA0A0A0
DrawBox     hdc,10,10,768,780,255*34825
For jx=0 To 49
DrawEllipse hdc,250,300,200+jx,150-jx, &H80FF80*jx
DrawEllipse hdc,620,300,150-jx,200+jx, &HFF80FF*jx
Next
DoEvents
FlipBuffer
Wend
CloseApp 


Peter

.
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: Charles Pegge on January 11, 2011, 01:36:21 PM
Nice one Peter!

I'm going to work on RTL64 as soon as I have done the dreaded annual tax returns.

Does anybody not have a 64 bit OS?

Charles
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: Peter on January 11, 2011, 01:40:31 PM

don't pay any tax, buy computer's!

Peter
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: efgee on January 11, 2011, 02:26:46 PM
Does anybody not have a 64 bit OS?

Here we have:

WinXP_32-SP3
Vista_32-SP2
Win7_64
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: efgee on January 11, 2011, 03:04:19 PM
Try putting an asterisk to the left of each param :)

Doing a manual byRef with an asterik like that:

Code: [Select]
Define *a.l = 4
Define *b.l = 2

Debug IsInitialized()
Debug MathAdd(*a,*b)
Debug MathDiv(4,2)
Debug MathMul(4,2)
Debug MathSub(4,2)

doesn't change a thing, it still crashes.

I suppose the PureBasic compiler is clever enough and treats params used by imported functions always byRef because the error message does not change...
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: JRS on January 11, 2011, 10:02:01 PM
Quote
Does anybody not have a 64 bit OS?

I do but so does anyone else for pennies an hour. You can pretty much create any Windows (32/64) or Linux (32/64) on a Amazon S2 server instance. You only pay (.14 to .20 US cents / hour) and you can suspend the instance which cost you nothing while not in use. I just don't have that big of a need at the moment to go out and buy a 64 bit box when what I have works fine.
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: jack on January 12, 2011, 05:52:00 AM
Code: [Select]
Define *a.l = 4
Define *b.l = 2

the asterisk means it's a pointer, but PureBasic treats pointers differently than C,
if I am not mistaken, the first two statements will set the pointer to point to memory location 4 and 2
not set the value of the variables as you intended, I will give it a shot and see what will work.
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: jack on January 12, 2011, 08:11:05 AM
I finaly managed to compile the dll, first thing I noticed is that the exported functions have upper/lower case characters,
in PureBasic when you import a function it treats the name as lower case, you need to declare as follows
Code: [Select]
Import "g:\Bunion\examples\dll_math_o2.lib"
  IsInitialized()     As "_IsInitialized"
  MathAdd(n1.i, n2.i) As "_MathAdd"
  MathDiv(n1.i, n2.i) As "_MathDiv"
  MathMul(n1.i, n2.i) As "_MathMul"
  MathSub(n1.i, n2.i) As "_MathSub"
EndImport

when I run the example I get this error from PureBasic
Quote
The application failed to initialize properly (0xc0000005). Click on OK to terminate the application.
I will give it try in FreeBasic an see what happens.
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: Charles Pegge on January 12, 2011, 08:28:35 AM
This is what I had in mind with regard to byref

PureBasic
Code: [Select]
Import "g:\Bunion\examples\dll_math_o2.lib"
  IsInitialized()
  MathMul(*n1.i, *n2.i)
  MathDiv(*n1.i, *n2.i)
  MathAdd(*n1.i, *n2.i)
  MathSub(*n1.i, *n2.i)
EndImport
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: jack on January 12, 2011, 09:20:41 AM
I got to kind of work in FreeBasic

FreeBasic code
Code: [Select]
#inclib "dll_math_o2"

declare function IsInitialized cdecl alias "IsInitialized" () as integer
declare function MathAdd cdecl alias "MathAdd" (byref as integer, byref as integer) as integer
declare function MathDiv cdecl alias "MathDiv" (byref as integer, byref as integer) as integer
declare function MathMul cdecl alias "MathMul" (byref as integer, byref as integer) as integer
declare function MathSub cdecl alias "MathSub" (byref as integer, byref as integer) as integer

Print IsInitialized()
Print MathMul(4,2)
Print MathDiv(4,2)
Print MathAdd(4,2)
Print MathSub(4,2)

print "press return to end ";
sleep

output
Quote
1
 8             2  6
-2954414
press return to end

if I try to use stdcall the linker looks for functions with @bytes at the end of the function,
will see if I can resolve that.
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: efgee on January 12, 2011, 09:24:56 AM
This is what I had in mind with regard to byref

PureBasic
Code: [Select]
Import "g:\Bunion\examples\dll_math_o2.lib"
  IsInitialized()
  MathMul(*n1.i, *n2.i)
  MathDiv(*n1.i, *n2.i)
  MathAdd(*n1.i, *n2.i)
  MathSub(*n1.i, *n2.i)
EndImport

Tried this yesterday (and different other variations...) but it crashes - not even the first function is called properly.
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: efgee on January 12, 2011, 09:31:22 AM
@Jack
thank you for helping out, would have tried with FreeBasic myself today...

Have to give HotBasic a spin and see if it has problems too...
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: efgee on January 12, 2011, 09:34:33 AM
Relocatability is achieved by avoiding absolute addresses completely. Addresses are referenced either relatively (for direct jumps and calls) or by offset from a register. EBX contains the absolute address of the .bssdata - the start of the uninitialised data section. All function tables and static variables are mapped out as an offset from this base.

How does register EBX obtain an absolute address to .bssdata at runtime? In 32 bit mode its a little awkward but this is what I do:
Code: [Select]
call fwd here
.here
pop ebx 'get the absolute address of here
sub ebx,here 'deduct virtual address of here
add ebx,bssdata 'add virtual address of bssdata

In 64 bit mode it's so much simpler:
Code: [Select]
lea rip rbx,bssdata 'load effective address (Relative to Instruction Pointer) .bssdata
(The notation will differ in other assemblers)

Didn't know this was even possible; I can't remember having seen such approach at all... until now.

 :)
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: jack on January 12, 2011, 11:51:19 AM
here's the FreeBasic Program with run-time loading, it works as expected.
Code: [Select]
''
'' this program -- loads dll_math_o2 at runtime, calls a dll_math_o2's function and prints the result
''
'' note: requires the compiled dll_math_o2 dynamic library to be available in current directory
''

dim library as any ptr
dim IsInitialized as function () as integer
dim MathAdd as function ( byref operand1 as integer, byref operand2 as integer ) as integer
dim MathDiv as function ( byref operand1 as integer, byref operand2 as integer ) as integer
dim MathMul as function ( byref operand1 as integer, byref operand2 as integer ) as integer
dim MathSub as function ( byref operand1 as integer, byref operand2 as integer ) as integer

'' Note we specify just "dll_math_o2" as library file name; this is to ensure
'' compatibility between Windows and Linux, where a dynamic library
'' has different file name and extension.
''
library = dylibload( "dll_math_o2" )
if( library = 0 ) then
print "Cannot load the dll_math_o2 dynamic library, aborting program..."
end 1
end if

IsInitialized = dylibsymbol( library, "IsInitialized" )
if( IsInitialized = 0 ) then
print "Cannot get IsInitialized function address from dll_math_o2 library, aborting program..."
end 1
end if
   
MathAdd = dylibsymbol( library, "MathAdd" )
if( MathAdd = 0 ) then
print "Cannot get MathAdd function address from dll_math_o2 library, aborting program..."
end 1
end if

MathDiv = dylibsymbol( library, "MathDiv" )
if( MathDiv = 0 ) then
print "Cannot get MathDiv function address from dll_math_o2 library, aborting program..."
end 1
end if

MathMul = dylibsymbol( library, "MathMul" )
if( MathMul = 0 ) then
print "Cannot get MathMul function address from dll_math_o2 library, aborting program..."
end 1
end if

MathSub = dylibsymbol( library, "MathSub" )
if( MathSub = 0 ) then
print "Cannot get MathSub function address from dll_math_o2 library, aborting program..."
end 1
end if
   
randomize timer

dim as integer x = 4
dim as integer y = 2

    ' print x; " +"; y; " ="; MathAdd( x, y )
    Print "IsInitialized()="; IsInitialized()
    Print x; " *"; y; " ="; MathMul(4,2)
    Print x; " /"; y; " ="; MathDiv(x, y)
    Print x; " +"; y; " ="; MathAdd(x, y)
    Print x; " -"; y; " ="; MathSub(4,2)
'' Done with the library; the OS will automatically unload libraries loaded by a process
'' when it terminates, but we can also force unloading during our program execution to
'' save resources; this is what the next line does. Remember that once you unload a
'' previously loaded library, all the symbols you got from it via dylibsymbol will become
'' invalid, and accessing them will cause the application to crash.
''
dylibfree library
   
    print "press return to end ";
    sleep
have not figured out how to use an import lib because when I try to compile with stdcall the linker complains
"can't find function IsInitialized@0" and so on for the rest of the functions.
if I modify the def file like this
Quote
LIBRARY dll_math_o2.dll
EXPORTS
IsInitialized@0              @1
MathAdd@8                    @2
MathDiv@8                    @3
MathMul@8                    @4
MathSub@8                    @5
and then re-create the import lib, it compiles and links OK but when run it gives the error "can't find IsInitialized@0 in dll"
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: jack on January 12, 2011, 12:22:36 PM
here's working PureBasic version

Code: [Select]
Import "dll_math_o2.lib"
  IsInitialized()
  MathAdd(*n1.i, *n2.i)
  MathDiv(*n1.i, *n2.i)
  MathMul(*n1.i, *n2.i)
  MathSub(*n1.i, *n2.i)
EndImport
x.i = 4
y.i = 2
Debug IsInitialized()
Debug MathMul(@x,@y)
Debug MathDiv(@x,@y)
Debug MathAdd(@x,@y)
Debug MathSub(@x,@y)

have to use variables, can't use constants when calling the functions.
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: Charles Pegge on January 12, 2011, 01:46:21 PM
Well done jack. And welcome to the Forum :)

FreeBasic and PureBasic make it quite complicated to hook up to a DLL. I am very familiar with FreeBasic which ships with a large number of .A (import library) files for all the commonly used DLLs. This is a requirement of the GNU linker. It's all very arcane.

Creating the .A file from the def file
Code: [Select]
dlltool -k -d Bah.def -l libBah.a

Incidently. If you want to create DLLs in FreeBasic without the @ name decoration, you define all the export subs and functions between:

Code: [Select]
    Extern "Windows-MS"
...
...
   End Extern

Charles
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: efgee on January 12, 2011, 02:08:17 PM
here's the FreeBasic Program with run-time loading, it works as expected.

...

here's working PureBasic version


Outstanding job!

 8)

Thank you very much.
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: jack on January 12, 2011, 02:27:19 PM
thanks Charles, efgee :)
I remember now that you mention it seeing a topic on the FreeBasic forum about Extern "Windows-MS" but completely forgot about it.
in my first FreeBasic attempt, I was declaring the functions as cdecl and it almost seemed to work, am sure had more functions been called
that eventually the program would have crashed due to stack corruption
but when I tried to use the stdcall method the linker complained that it coud not find IsInitialized@0 and similarly for the rest of the functions
when I added the @size to the functioncs in the def file and rebuilt the lib, it compiled OK, but when run it would give the error
IsInitialized@0 not found in the dll, so I am at a loss for the moment on how to use o2 dll's using an import lib in FB.
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: efgee on January 12, 2011, 02:40:59 PM
Another PureBasic approach using PureBasic's prototypes:

Code: [Select]
; using prototypes
#Library = 1

Prototype.i mathFunc(*val1.l, *val2.l)

Define a.i = 4
Define b.i = 2

If OpenLibrary(#Library, "dll_math_o2.dll")
 
  If ExamineLibraryFunctions(#Library)
   
    While NextLibraryFunction()
     
      func.mathFunc = GetFunction(#Library, LibraryFunctionName())
      Debug LibraryFunctionName() + " : $" + Hex(LibraryFunctionAddress())
      Debug func(@a, @b)
     
    Wend
   
  EndIf
 
EndIf

CloseLibrary(#Library)

I like Prototypes (as PureBasic calls them) very much; maybe Charles too...
...and writes a reminder in his OxygenBasic to-do list  ;D

.
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: Charles Pegge on January 12, 2011, 02:51:40 PM
Well thanks for leading the topic efgee. Do you prefer prototypes to declarations ?  "Declare" reminds me of form filling and taxes but could also be declaration of human rights :)

Just to clarify: in Oxygen you can specify aliases for both imported and exported functions. If the alias is unspecified then the external name is derived from the function/sub name without any alteration (no case conversion either). Internally, Oxygen is not normally sensitive to the case of function names.

The default calling convention is stdcall in 32 bit MS and will be cdecl in 32 bit Linux. In the 64 bit modes it is totally weird and warped by the contortions of the Pentium architecture, and devised exclusively for the convenience of kernel writers. (I am not enthusiastic as you might guess).

Charles
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: jack on January 12, 2011, 03:42:14 PM
using alias to decorate the names

o2 code
Code: [Select]
$ dll
  $ FileName dll_math_o2
  includepath "..\inc\"
  include "RTL32.inc"

function IsInitialized alias "IsInitialized@0"() as long export
function = (1)
end function

function MathAdd alias "MathAdd@8"(N1 as long, N2 as long) as long export
function = (N1 + N2)
end function

function MathDiv alias "MathDiv@8"(N1 as long, N2 as long) as long export
function = (N1 / N2)
end function

function MathMul alias "MathMul@8"(N1 as long, N2 as long) as long export
function = (N1 * N2)
end function

function MathSub alias "MathSub@8"(N1 as long, N2 as long) as long export
function = (N1 - N2)
end function


the following FreeBasic code works as expected

FreeBasic code

Code: [Select]
#inclib "dll_math_o2"

declare function IsInitialized alias "IsInitialized" () as integer
declare function MathAdd alias "MathAdd" (byref as integer, byref as integer) as integer
declare function MathDiv alias "MathDiv" (byref as integer, byref as integer) as integer
declare function MathMul alias "MathMul" (byref as integer, byref as integer) as integer
declare function MathSub alias "MathSub" (byref as integer, byref as integer) as integer

Print IsInitialized()
Print MathMul(4,2)
Print MathDiv(4,2)
Print MathAdd(4,2)
Print MathSub(4,2)

print "press return to end ";
sleep
[edit]  unsing alias to decorate the name is a bad idea, better example by Charles below this post.
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: Charles Pegge on January 12, 2011, 04:01:20 PM
jack,

I was able to avoid alias name decorations in the O2 DLL. I've put all the bits and pieces into the zip below. It's all very complicated!

Charles

.
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: jack on January 12, 2011, 04:44:52 PM
Charles, I had tried something very similar but it did not work, while your example does work
I used pexports to make the def file
pexports -o dll_math_o2.dll >dll_math_o2.def
what I got was
Quote
LIBRARY dll_math_o2.dll
EXPORTS
IsInitialized           @1
MathAdd                  @2
MathDiv                  @3
MathMul                  @4
MathSub                  @5

I then added the @size
Quote

LIBRARY dll_math_o2.dll
EXPORTS
IsInitialized@0            @1
MathAdd@8                  @2
MathDiv@8                  @3
MathMul@8                  @4
MathSub@8                  @5

recreating the lib with that def file did not work
I also made def file with gendef with the command
gendef dll_math_o2.dll
and got
Quote
;
; Definition file of dll_math_o2.dll
; Automatic generated by gendef
; written by Kai Tietz 2008
;
LIBRARY "dll_math_o2.dll"
EXPORTS
IsInitialized
MathAdd@8
MathDiv@8
MathMul@8
MathSub@8
but did not recreate the lib with that.

[edit] adding the k flag to dlltool as in your example did the trick
Title: Re: Using a O2 DLL with apps generated with other compilers
Post by: Charles Pegge on January 13, 2011, 12:35:07 PM
If found a couple of useful links on DEF files as used in Visual C


DEF Files in Visual Studio

2010

http://msdn.microsoft.com/en-us/library/28d6s79h.aspx

2008 forum

http://stackoverflow.com/questions/26098/overloaded-functions-in-c-dll-def-file

Charles