DOS drivers in FreeBASIC

DOS specific questions.
Post Reply
Gablea
Posts: 1104
Joined: Apr 06, 2010 0:05
Location: Northampton, United Kingdom
Contact:

DOS drivers in FreeBASIC

Post by Gablea »

Hi everyone,

I want to ask a question. As most of you know I am writing a EPoS application in FreeBASIC and I want to ask a question.

Can I move all the function for example of my printer into a separate driver file or TSR that is loaded when my systems boots?

I ask this as I am struggling to keep all the different printer codes in order and I was thinking about something like

tmu950.drv for the Epson 2.5 slip printer and to use it my app would look into the \EPoS\Drivers folder and load the given drivers that are there

A topical example could be

tm88iii.drv
cashdwr.drv
custdisp.drv
serials can.drv

So when the program loads it would display

Loading drivers
Loaded Epson TM88iii thermal Printer driver version 1.23.6
Could the name and version number come from the driver module itself?

But I'm not sure how my program would access the code that is with in the drivers.

Any advise would be welcomed as I would need this to also run on Linux at some point.
angros47
Posts: 2321
Joined: Jun 21, 2005 19:04

Re: DOS drivers in FreeBASIC

Post by angros47 »

Nice to see you again, Gablea, it has been a while

As I explained to you in the past, while technically possible, making a TSR in FreeBasic is not a good idea. It's extremely unstable, documentation about it is lacking, and as far as I know no one ever used it for any practical use (I just ported an example from DJGPP, to show that it's possible, but even in C++ the only example I know about was 20 years old.

What you seem to need is a dynamic library: a module with all the functions from the printer, several interchangeable modules, a parameter (perhaps an environment variable) that tells your program which module to load.

Since version 1.06 FreeBasic allows to use dynamic libraries under DOS (using the format DXE). If you use this approach, when you will port your program to Linux you could keep the same approach (the Linux version of FreeBasic will just compile the dynamic module to .so format and everything will work in the same way)
Gablea
Posts: 1104
Joined: Apr 06, 2010 0:05
Location: Northampton, United Kingdom
Contact:

Re: DOS drivers in FreeBASIC

Post by Gablea »

Hi @angros47

Does that mean I could use a DLL that was written for windows in my FreeBASIC program?

If so do you know any examples that I could look at? And any example code of how to access the DLL functions?
angros47
Posts: 2321
Joined: Jun 21, 2005 19:04

Re: DOS drivers in FreeBASIC

Post by angros47 »

Only if you have the source code of the library.
If all you have is the DLL file, you cannot.

Are you planning to use a library written by you in FreeBasic, or you want to use a standard library provided by the hardware manufacturer?
Gablea
Posts: 1104
Joined: Apr 06, 2010 0:05
Location: Northampton, United Kingdom
Contact:

Re: DOS drivers in FreeBASIC

Post by Gablea »

I have the source code to a DLL that I want to use (this adds promotional support to my windows app)

And i would be creating new dlls for the printers I support

How would the application know what DLL to use? Or do I have to compile it with every DLL included and then work that code internally?
angros47
Posts: 2321
Joined: Jun 21, 2005 19:04

Re: DOS drivers in FreeBASIC

Post by angros47 »

Ok. To create a dynamic library in DOS, you have to use version 1.06 or later of FreeBasic

File mydll.bas

Code: Select all

''
'' mydll -- simple dll test
''
'' compile as: fbc -dll mydll.bas
''
'' (will create mydll.dxe under DOS)

#include once "mydll.bi"

'' simple exported function, the full prototype is in mydll.bi.
'' (the EXPORT clause must be used here)
function AddNumbers( byval a as integer, byval b as integer) as integer export
	function = a + b
end function
Header: file mydll.bi

Code: Select all

declare function AddNumbers alias "AddNumbers"( byval a as integer, byval b as integer ) as integer

To load and use the dynamic library:

Code: Select all

''
'' Loads mydll at runtime, calls a mydll's function and prints the result
'' 
'' compile as: fbc dylib.bas
'' (mydll must be compiled first)
''

dim library as any ptr

'' Function pointer through which the function is going to be called
dim AddNumbers as function( byval a as integer, byval b as integer ) as integer

'' Note: under DOS you must specify "mydll.dxe", differently from Windows or Linux

library = dylibload( "mydll.dxe" )
if( library = 0 ) then
	print "Cannot load the mydll dynamic library"
	sleep
	end 1
end if

'' Here the exact function name exported by the DLL must be given:
'' If ALIAS "..." was used then it is the exact specified alias name,
'' otherwise it's the normal name but all UPPERCASED (BASIC name mangling).
'' (EXTERN ... END EXTERN blocks also change name mangling modes if used)
addnumbers = dylibsymbol( library, "_AddNumbers" )
if( addnumbers = 0 ) then
	print "Could not get AddNumbers()'s address from mydll library"
	end 1
end if

randomize( timer( ) )

dim as integer x = rnd * 10
dim as integer y = rnd * 10

print x; " +"; y; " ="; AddNumbers( x, y )

'' Done with the library. The OS will automatically clean up, but we can also
'' unload earlier (before process exit) if it's no longer needed.
'' Once it's unloaded, all function pointers to it become invalid!
dylibfree library
How would the application know what DLL to use? Or do I have to compile it with every DLL included and then work that code internally?
You can have several dynamic libraries in the same directory, and have a config file that specifies which printer is installed. Then, you read from the config file the installed printer and load the according driver, something like:

Code: Select all

Open "config.ini" for input as #1
line input #1, drivername
if drivername="epson" then library = dylibload( "epson.dxe" )
if drivername="HP" then library = dylibload( "hp.dxe" )

or even

Code: Select all

Open "config.ini" for input as #1
line input #1, drivername
library = dylibload(drivername)

Otherwise, you can just have something like:

Code: Select all

library = dylibload( "printer.dxe" )
and when you install your software, the installer can ask which printer is available and copy the correct driver on the file "printer.dxe"
Gablea
Posts: 1104
Joined: Apr 06, 2010 0:05
Location: Northampton, United Kingdom
Contact:

Re: DOS drivers in FreeBASIC

Post by Gablea »

angros47 wrote: Jun 05, 2022 13:00 Header: file mydll.bi

Code: Select all

declare function AddNumbers alias "AddNumbers"( byval a as integer, byval b as integer ) as integer

Hi angros47

So from what I have read of your example (Thank you for that by the way very helpful) the function Name can be the same for all the printers dll (dxe files) and if I want for example to Print a Large Char on a Epson I can call Largetext("Welcome",Centre) and the same function would work for NCR (but runs the NCR DLL code)

Epson Example

Code: Select all

Public Sub LargeText (ByVal LineToPrint as String, ByVal lineAglinment as string)
Private DataToPrint as string

DataToPrint += CHR$(&H1B) & ";" & "=" & ";" & Chr$(1) ' Select the Printer Only
DataToPrint += Chr$(&H1B) & "!" & Chr$(16) & LineToPrint & Chr(10) & Chr(13) ' Saves the Text to Print

Print #PoSPrinter, DataToPrint;
End SUb
NCR Example

Code: Select all

Public Sub LargeText (ByVal LineToPrint as String, ByVal lineAglinment as string)
Private DataToPrint as string
DataToPrint = Chr$(&H1B) & "!" & Chr$(56) & LineToPrint & Chr(10) & Chr(13) 
Print #PoSPrinter, DataToPrint;
End Sub
angros47
Posts: 2321
Joined: Jun 21, 2005 19:04

Re: DOS drivers in FreeBASIC

Post by angros47 »

Yes, exactly. You will just have to avoid loading both libraries at the same time, of course. Likely your program can read a configuration file, and load the appropriate library.
TJF
Posts: 3809
Joined: Dec 06, 2009 22:27
Location: N47°, E15°
Contact:

Re: DOS drivers in FreeBASIC

Post by TJF »

angros47 wrote: Jul 02, 2022 22:51 You will just have to avoid loading both libraries at the same time, of course.
That's correct when compiling/linking against the library. But DYLIBLOAD provides different pointers to the binaries loaded, so multiple libs can be active at the same time. Example

Code: Select all

TYPE AddNumbers AS FUNCTION(BYVAL a AS INTEGER, BYVAL b AS INTEGER)AS INTEGER

'' Note: under DOS you must specify "mydll.dxe", differently from Windows or Linux

VAR EpsonLib = DYLIBLOAD("epson.dxe")
DIM AS AddNumbers EpsonAdd
IF EpsonLib THEN
  EpsonAdd = DYLIBSYMBOL(EpsonLib, "_AddNumbers")
  IF 0 = EpsonAdd THEN
    PRINT "Could not get AddNumbers()'s address from EpsonLib library"
    DYLIBFREE EpsonLib
    END 1
  END IF
ELSE
  PRINT "Cannot load the EpsonLib dynamic library"
  SLEEP
  END 1
END IF

VAR NfcLib = DYLIBLOAD("nfc.dxe")
DIM AS AddNumbers NfcAdd
IF NfcLib THEN
  NfcAdd = DYLIBSYMBOL(NfcLib, "_AddNumbers")
  IF 0 = NfcAdd THEN
    PRINT "Could not get AddNumbers()'s address from NfcLib library"
    DYLIBFREE NfcLib
    DYLIBFREE EpsonLib
    END 1
  END IF
ELSE
  DYLIBFREE EpsonLib
  PRINT "Cannot load the NfcLib dynamic library"
  SLEEP
  END 1
END IF


RANDOMIZE( TIMER( ) )

DIM AS INTEGER x = RND * 10
DIM AS INTEGER y = RND * 10

PRINT x; " +"; y; " ="; EpsonAdd(x, y)
PRINT x; " +"; y; " ="; NfcAdd(x, y)

DYLIBFREE EpsonLib
DYLIBFREE NfcLib

That may be useful when there're multiple printers at a client.
Post Reply