Author Topic: Tutorial: How do DECLARE LIBRARY/DECLARE DYNAMIC LIBRARY actually work?  (Read 1696 times)

Galleon

  • Administrator
  • Hero Member
  • *****
  • Posts: 4699
  • QB Forever
    • Email
DECLARE LIBRARY
Let's look at some examples:
Code: [Select]
DECLARE LIBRARY
    FUNCTION fabs# (BYVAL value#)
END DECLARE
The C function 'fabs' is already available to the outputted C++ code, we are just telling QB64 how to call it.
Note: What is/isn't available is not formally defined, nor is it guaranteed to stay that way in future versions of QB64.

Code: [Select]
DECLARE LIBRARY ""
    FUNCTION addone& (BYVAL value&)
END DECLARE
The C function 'addone' exists in a library QB64 already links to, but it hasn't been defined as a C function or a QB64 function. By using "" we are telling QB64 the function exists in a library which is already linked to and that it must define the C function for calling it, as well as allowing QB64 code to call it. Trying the above code without the "" will fail.
Note: What libraries are/aren't automatically used in the linking process is not formally defined, nor is it guaranteed to stay that way in future versions of QB64.

For this next example, you'll need to download the file 'add.lib' and place it in you QB64 folder: http://www.qb64.net/add.lib
Tip: Never use a .LIB from an untrusted source.
Code: [Select]
DECLARE LIBRARY "add"
    FUNCTION addtwo& (BYVAL value&)
END DECLARE
PRINT addtwo(1)
Here, we tell QB64 to link to 'add.lib' (QB64 searches for 'add.lib', 'add.a', and 'add.o' in that order and uses the first that it finds). The function 'addtwo' exists inside the library file 'add.lib' but isn't defined anywhere else. QB64 creates the C definition for the function 'addtwo' so that it can be called from our QB64 code.
Note: If the C function definition auto-created by QB64 does not exactly match the definition in the library file, it will not work. As a result of this it is often better to provide the C function definitions in the form of a C header file, such as in the following example.

NTport is a commercial library hosted at http://www.zealsoftstudio.com/ntport/, but it does provide an evaluation version (it has a 3 second wait pop-up window) which we will use here. You don't need to download NTport, just download the following 3 files and put them in your QB64 folder:
http://www.qb64.net/ntport/ntport.lib
http://www.qb64.net/ntport/ntport.h
http://www.qb64.net/ntport/ntport.dll
IMPORTANT: The DLL is loaded automatically by the static library, we are not linking directly to the DLL, so we are still static linking not dynamically linking. This is an important concept to understand.
Code: [Select]
DECLARE LIBRARY "ntport"
    FUNCTION GetLPTPortAddress% (BYVAL PortNo%)
END DECLARE
PRINT "&H" + HEX$(GetLPTPortAddress%(1))
DECLARE LIBRARY also searches for C header files with a '.h' extension. So in this case it is using the header 'ntport.h' and linking with 'ntport.lib' just by specifying "NTPORT". The C function definitions are stored in 'ntport.h' so even if our QB64 functions don't exactly match (eg. LONG instead of INTEGER) it will still work.
If you look inside 'ntport.h' you'll find the following line containing the C function definition of the command we used:
Code: [Select]
WORD WINAPI GetLPTPortAddress(WORD PortNo);
more to come on this...

DECLARE DYNAMIC LIBRARY

DECLARE DYNAMIC LIBRARY allows you to dynamically link your program to functions in dynamically linkable libraries. At present, only '.DLL' files are supported (support for '.so' will be added soon). These libraries are loaded when your program begins.

The dynamic library file can be located in the QB64 folder (alongside your programs '.EXE'), in Windows' system folder, or in a relative/absolute path specified along with the library name.

'.h' header files cannot be used with DECLARE DYNAMIC LIBRARY. Existence of any '.h' file of the same name as the '.DLL' file will cause DECLARE DYNAMIC LIBRARY to fail.

Only one '.DLL' file can be specified in each DECLARE DYNAMIC LIBRARY block.

The best way to understand DECLARE DYNAMIC LIBRARY is to disregard almost everything you have learned about DECLARE LIBRARY, particularly about the C type matching.

IMPORTANT: DECLARE DYNAMIC LIBRARY let's you specify any SUB/FUNCTION calling format you wish, but if the size of the parameters does not match the size expected within the library your code will probably cause a GPF! It is important to understand that you are creating a 32-bit program (even under 64-bit Windows) so pointers (if required) will be 32-bits in size, the equivalent of a LONG.

QB64 can already play MIDI files, but we'll use a DLL to do this instead for this example.
For reference purposes, the DLL is documented here:http://libertybasicuniversity.com/lbnews/nl110/midi3.htm
Download the following DLL file to your main QB64 folder:
http://www.qb64.net/playmidi32.dll
Note: The filename needs to be CHR$(0) terminated. QB64 STRINGs are passed to external libraries as pointers to their first character.
Code: [Select]
DECLARE DYNAMIC LIBRARY "playmidi32"
    FUNCTION PlayMIDI& (filename AS STRING)
END DECLARE
result = PlayMIDI(".\samples\qb64\original\ps2battl.mid" + CHR$(0))
PRINT result

more to come on this...
« Last Edit: December 14, 2010, 04:26:22 AM by Galleon »
Something old... Something new... Something borrowed... Something blue...

Clippy

  • Hero Member
  • *****
  • Posts: 16446
  • I LOVE π = 4 * ATN(1)    Use the QB64 WIKI >>>
    • Pete's Qbasic Site
    • Email
Re: Tutorial: How do DECLARE LIBRARY/DECLARE DYNAMIC LIBRARY actually work?
« Reply #1 on: December 14, 2010, 10:44:35 AM »
I assume that ALIAS is allowed also. Are all QB64 strings sent zero terminated? What about the DLL string returns?

How will LIBRARIES handle optional variables? Does C have an InputBox? I tried that and compilation failed...

Ted
« Last Edit: December 14, 2010, 06:24:54 PM by Clippy »
QB64 WIKI: Main Page
Download Q-Basics Code Demo: Q-Basics.zip
Download QB64 BAT, IconAdder and VBS shortcuts: QB64BAT.zip
Download QB64 DLL files in a ZIP: Program64.zip

Galleon

  • Administrator
  • Hero Member
  • *****
  • Posts: 4699
  • QB Forever
    • Email
Re: Tutorial: How do DECLARE LIBRARY/DECLARE DYNAMIC LIBRARY actually work?
« Reply #2 on: December 15, 2010, 02:50:43 AM »
Quote
I assume that ALIAS is allowed also.
Yes.

Quote
Are all QB64 strings sent zero terminated?
No. Some functions which require a buffer ask for the size of the buffer and you specify it as another parameter, in those cases CHR$(0) is not required.

Quote
What about the DLL string returns?
STRING returns are the same from either dynamic or static libraries, they convert a NULL-terminated 'char*' string into a non-NULL-terminated QB64 string.

Quote
How will LIBRARIES handle optional variables?
External libraries don't support the concept of optional variables.

Quote
Does C have an InputBox?
Ask someone else about this.
Something old... Something new... Something borrowed... Something blue...

GarryRicketson

  • Guest
Re: Tutorial: How do DECLARE LIBRARY/DECLARE DYNAMIC LIBRARY actually work?
« Reply #3 on: December 17, 2010, 10:37:33 PM »

Because this sound serious, I need to ask, What is a GPF,? is that
General Program Failure,...or something more serious,
Quote
     but if the size of the parameters does not match the size expected within the library your code will probably cause a GPF!
P.S, I am not jokeing, ....anyway, it is clear, it is important to keep the size of any parameters, matching, the size expected within the library.
thanks From
Garry

Galleon

  • Administrator
  • Hero Member
  • *****
  • Posts: 4699
  • QB Forever
    • Email
Re: Tutorial: How do DECLARE LIBRARY/DECLARE DYNAMIC LIBRARY actually work?
« Reply #4 on: December 17, 2010, 10:42:09 PM »
General Protection Fault.

It's not that severe, but it will stop the program you are running and could potentially cause problems to any files your program is reading to/writing from. It usually arises from attempting to read/write to a memory location you program does not have permission to use.
Something old... Something new... Something borrowed... Something blue...

Clippy

  • Hero Member
  • *****
  • Posts: 16446
  • I LOVE π = 4 * ATN(1)    Use the QB64 WIKI >>>
    • Pete's Qbasic Site
    • Email
Re: Tutorial: How do DECLARE LIBRARY/DECLARE DYNAMIC LIBRARY actually work?
« Reply #5 on: December 17, 2010, 10:44:09 PM »
General Protection Fault may shut the computer down immediately. This is to prevent serious damage, but that COULD happen anyhow.

IE, BE CAREFUL! If you're not sure, DON'T DO IT!
QB64 WIKI: Main Page
Download Q-Basics Code Demo: Q-Basics.zip
Download QB64 BAT, IconAdder and VBS shortcuts: QB64BAT.zip
Download QB64 DLL files in a ZIP: Program64.zip

GarryRicketson

  • Guest
Re: Tutorial: How do DECLARE LIBRARY/DECLARE DYNAMIC LIBRARY actually work?
« Reply #6 on: December 17, 2010, 10:58:11 PM »
OK, thanks, since this stuff with the Librarys is new to me,..sounds like I may be better off, posting any code, to see if it looks ok first,..I'll be careful,...Thanks
from Garry

Jack

  • Newbie
  • *
  • Posts: 13
Re: Tutorial: How do DECLARE LIBRARY/DECLARE DYNAMIC LIBRARY actually work?
« Reply #7 on: December 18, 2010, 10:05:33 AM »
Galleon, what C/C++ compiler do you use?
the reason I am asking is that I am interested in experimenting/programming with QB64 and noticed the name mangling of your add.lib
the function addtwo as seen with LibDump is __Z6addtwoi , also can we use a declare that looks something like this?
Quote
DECLARE LIBRARY "add"
 Function addtwo          Cdecl Alias "__Z6addtwoi"          ( Byval value&)
END DECLARE

Clippy

  • Hero Member
  • *****
  • Posts: 16446
  • I LOVE π = 4 * ATN(1)    Use the QB64 WIKI >>>
    • Pete's Qbasic Site
    • Email
Re: Tutorial: How do DECLARE LIBRARY/DECLARE DYNAMIC LIBRARY actually work?
« Reply #8 on: December 18, 2010, 11:20:44 AM »
ALIAS can be used inside a DECLARE LIBRARY ONLY, but CDECL is unecessary and is not supported in QB64 "yet" if ever.
QB64 WIKI: Main Page
Download Q-Basics Code Demo: Q-Basics.zip
Download QB64 BAT, IconAdder and VBS shortcuts: QB64BAT.zip
Download QB64 DLL files in a ZIP: Program64.zip

rthorpe

  • Guest
Re: Tutorial: How do DECLARE LIBRARY/DECLARE DYNAMIC LIBRARY actually work?
« Reply #9 on: December 18, 2010, 12:21:38 PM »
Jack,

I think the symbol you have is the result of "C++ name mangling".  Which is the way that C++'s complicated system of function naming is mapped into object code. I don't think you have to worry about it unless you're using a C style debugger on the output of QB64.

Jack

  • Newbie
  • *
  • Posts: 13
Re: Tutorial: How do DECLARE LIBRARY/DECLARE DYNAMIC LIBRARY actually work?
« Reply #10 on: December 18, 2010, 12:33:57 PM »
what if you have a library that was compiled in C which mangles the name differently?
or what if for some reason the lib uses stdcall instead of cdecl calling convention? (which happens with windows dll's)

rthorpe

  • Guest
Re: Tutorial: How do DECLARE LIBRARY/DECLARE DYNAMIC LIBRARY actually work?
« Reply #11 on: December 18, 2010, 12:44:52 PM »
> what if you have a library that was compiled in C which mangles the name differently?

I don't know how you deal with that. I know it's difficult to get C++ libraries compiled with different compilers to work properly together.

> or what if for some reason the lib uses stdcall instead of cdecl calling convention? (which happens with windows dll's)

Compilers often provide a way of dealing with that by adding a calling convention after the function prototype. The problem with that system though that it isn't standard. GCC has one set of reserved words for specifying it and MSVC has another.

Artelius

  • Guest
Re: Tutorial: How do DECLARE LIBRARY/DECLARE DYNAMIC LIBRARY actually work?
« Reply #12 on: December 23, 2010, 02:53:05 PM »
General Protection Fault may shut the computer down immediately. This is to prevent serious damage, but that COULD happen anyhow.

IE, BE CAREFUL! If you're not sure, DON'T DO IT!

Not at all. A GPF caused by an application program will not damage your computer (although it usually terminates the application). They are the sources of errors such as "Internet Explorer has encountered a problem and needs to close. We are sorry for the inconvenience." On UNIX-like systems this error is called a segmentation fault.

A GPF within the OS kernel is another matter, but those are caused by OS bugs, not your bugs.

rthorpe

  • Guest
Re: Tutorial: How do DECLARE LIBRARY/DECLARE DYNAMIC LIBRARY actually work?
« Reply #13 on: December 23, 2010, 04:35:12 PM »
Artlelius is right for modern OSes. Post Windows 95 any GPF that leads to a system crash is a Microsoft bug. It's the same with Unix variants, no program should be able to cause a system crash, if it does then that's an OS bug.

mcalkins

  • Hero Member
  • *****
  • Posts: 1282
    • qbasicmichael.com
    • Email
Re: Tutorial: How do DECLARE LIBRARY/DECLARE DYNAMIC LIBRARY actually work?
« Reply #14 on: September 14, 2011, 05:37:30 AM »
>Artlelius is right for modern OSes. Post Windows 95 any GPF that leads to a system crash is a Microsoft bug. It's the same with Unix variants, no program should be able to cause a system crash, if it does then that's an OS bug.

And 3rd party device drivers, and faulty hardware.

Regards,
Michael
The QBASIC Forum Community: http://www.network54.com/index/10167 Includes off-topic subforums.
QB64 Off-topic subforum: http://qb64offtopic.freeforums.org/