Go home
Go back to other tutorials
Harbour How To - Tutorial
Giovanni Di Maria - calimero22@yahoo.it
since: Apr 06, 2011
Tutorial
Harbour 3.2
This Tutorial:
Rev. [1] - April 06, 2011
Rev. [287] - Feb 8, 2013
Index
Introduction
This tutorial is a brief, continuously updated, of the use of the Harbour language.
It is specifically written for beginners that initially encountered some difficulties in using
Harbour language, extremely powerful and efficient.
The approach of the tutorial is different from other guides that are online.
It simply focuses a single problem, so you do not get lost in the
maze of the vast files of examples provided with the product.
This will easily learn to manage an individual idea, as needed, and, finally,
to put "together" the whole.
Giovanni Di Maria
Notes for developers
- If possible, you must not use static variables
- If you use static variables, you have to set them to NIL at exit of the program
- It is strongly recommended to use hbformat tool to format the .prg sources
- To create a source, you can copy and paste the code to your text editor and save it with .prg extension
- The sources are formatted with "hbformat.exe" utility
Compiling in Windows
In order to compile correctly your sources, you must follow this procedure:
- Create the file named sample.hbp (or other name) as follow:
- -w3 -es2
- sample.prg
- otherprogrs.prg
- Create your source program, named sample.prg (or other name).
- Set your path to harbour/bin directory and mingw/bin directory.
- Compile with hbmk2 sample.hbp.
- The procedure will create the file sample.exe.
Legal Notices
This tutorial is a free document and will remain free. You can view, use, print and
redistribute it and/or modify it, without any limitations.
Array - Associative Array
The following example shows how to create an associative array. The index of array is a
string and not a number. (by Giovanni Di Maria)
PROCEDURE Main()
LOCAL aArray
LOCAL k
CLEAR SCREEN
aArray := { => }
aArray["dog"] := "fuffy"
aArray["cat"] := 1975
aArray["pig"] := "Giovanni Di Maria"
aArray["frog"] := 1234567890
? aArray["dog"] // -> fuffy
? aArray["cat"] // -> 1975
? "--------------"
FOR EACH k IN aArray
? k
NEXT k
RETURN
Array - Hash
The following example shows how to create an hash table. (by Giovanni Di Maria)
PROCEDURE Main()
LOCAL hVar := { 1 => .T. , "casa" => .F. , 5 => "hola" }
LOCAL x
CLEAR SCREEN
FOR EACH x IN hVar
? x
NEXT
? "--------------------"
? hVar[1]
? hVar["casa"]
? hVar[5]
RETURN
C Language - C function without parameters
The following example shows how to create a language C function. You can use it
in your .PRG sources. You have to create two files: the .PRG file, containing the Harbour
program and the .C file, containing the function, in C language. Give the sources
different names, otherwise their obj files will collide. In this example, you
have test.prg and func.c files. You can compile with:
hbmk2 test.prg func.c. (by Giovanni Di Maria)
// test.prg
PROCEDURE Main()
CLEAR SCREEN
? "Result=", udf()
RETURN
/* func.c */
#include "hbapi.h"
HB_FUNC(UDF) {
unsigned int a,b,c;
a=16;
b=5;
c=a+b;
hb_retni(c);
}
C Language - C function with parameters
The following example shows how to create a language C function. You can use it
in your .PRG sources. You have to create two files: the .PRG file, containing the Harbour
program and the .C file, containing the function, in C language. Give the sources
different names, otherwise their obj files will collide. In this example, you
have test.prg and func.c files. You can compile with:
hbmk2 test.prg func.c. (by Giovanni Di Maria)
// test.prg
PROCEDURE Main()
CLEAR SCREEN
? "The result is: ", multiply( 58, 37 )
RETURN
/* func.c */
#include "hbapi.h"
HB_FUNC(MULTIPLY) {
unsigned int a,b,c;
a=hb_parni(1);
b=hb_parni(2);
c=a*b;
hb_retni(c);
}
C Language - C function that returns a random number
The following example shows how to create a language C function, returning a random number.
You can use it in your .PRG sources. You have to create two files: the .PRG file,
containing the Harbour program and the .C file, containing the function, in C language.
Give the sources different names, otherwise their obj files will collide. In this example, you
have test.prg and func.c files. You can compile with:
hbmk2 test.prg func.c. (by Giovanni Di Maria)
// test.prg
PROCEDURE Main()
LOCAL k
CLEAR SCREEN
FOR k = 1 TO 10
? "A random number between 1 and 6 is: ", rnd( 6 )
NEXT k
RETURN
/* func.c */
#include "hbapi.h"
HB_FUNC(RND) {
hb_retni(rand()%hb_parni(1)+1);
}
C Language - C function that returns the sum of a range od numbers
The following example shows how to create a language C function, returning the sum of numbers,
from n1 to n2. The function is very fast and uses long long variables.
You can use it in your .PRG sources.
You have to create two files: the .PRG file, containing the Harbour program
and the .C file, containing the function, in C language.
Give the sources different names, otherwise their obj files will collide. In this example, you
have test.prg and func.c files. You can compile with:
hbmk2 test.prg func.c. (by Giovanni Di Maria)
// test.prg
PROCEDURE Main()
LOCAL n1, n2
n1 = 1
n2 = 896885789
? "The Sum from", n1, "to", n2, "is", somma( n1, n2 )
RETURN
/* func.c */
#include "hbapi.h"
HB_FUNC(SOMMA) {
long long a,b,t,k;
a=hb_parnint(1);
b=hb_parnint(2);
t=0;
for(k=a;k<=b;k++)
t+=k;
hb_retnint(t);
}
Mouse - Mouse on Get fields
The following example shows how to enable the mouse over the input fields. You can click
on the fields, instead to press Tab key, to navigate through the fields. (by Giovanni Di Maria)
#include "inkey.ch"
PROCEDURE MAIN
LOCAL GetList := {}
LOCAL cVar1, cVar2, cVar3
CLEAR SCREEN
cVar1 = Space( 10 )
cVar2 = Space( 10 )
cVar3 = Space( 10 )
SET( _SET_EVENTMASK, INKEY_ALL )
MSetCursor( .T. )
@ 10, 20 SAY "Var 1:" GET cVar1
@ 11, 20 SAY "Var 2:" GET cVar2
@ 12, 20 SAY "Var 3:" GET cVar3
READ
RETURN
MDB Database - Reading a table in MDB database
The following example shows how to read data from a MDB database. The name of
database is test.mdb. The database has a table, called tab_people. This table has the
following fields: first, last, age, mydate.
Compile the program with:
hbmk2 test.prg hbwin.hbc -w3. (by Giovanni Di Maria)
#define adOpenForwardOnly 0
#define adOpenKeyset 1
#define adOpenDynamic 2
#define adOpenStatic 3
#define adLockReadOnly 1
#define adLockPessimistic 2
#define adLockOptimistic 3
#define adLockBatchOptimistic 4
#define adUseNone 1
#define adUseServer 2
#define adUseClient 3
PROCEDURE MAIN()
LOCAL oRs , cSql, cDb
oRs := win_oleCreateObject( "ADODB.Recordset" )
cDb := "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=test.mdb"
cSql := "SELECT * FROM tab_people ;"
oRs:Open( cSql , cDb , adOpenForwardOnly, adLockReadOnly )
WHILE !oRs:EOF
? oRs:Fields( "First" ):Value
? oRs:Fields( "Last" ):Value
? oRs:Fields( "Age" ):Value
? oRs:Fields( "MyDate" ):Value
? "------------------------------------"
oRs:MoveNext()
ENDDO
oRs:Close()
RETURN
Standard Output - Standard Output
If a program with the statement "?" is redirected to a file o printer, it does not work. The
following example shows how to write values to the standard output device. In this case,
the output of the program ca be redirected to a different device (with > redirector).
(by Giovanni Di Maria)
PROCEDURE Main()
LOCAL k
FOR k = 1 TO 5
OutStd( k, hb_eol() )
NEXT k
RETURN
Compiling Info - Compiling Info
The following example shows how to retrieve informations about the compilator used. (by Giovanni Di Maria)
#include "hbver.ch"
PROCEDURE Main()
LOCAL k
? "Harbour build date: " + hb_Version( HB_VERSION_BUILD_DATE_STR )
? "Major version number: " , hb_Version( HB_VERSION_MAJOR )
? "Minor version number: " , hb_Version( HB_VERSION_MINOR )
? "Revision number: " , hb_Version( HB_VERSION_RELEASE )
? "Build status: " , hb_Version( HB_VERSION_STATUS )
? "-------------------------------------------------------------------"
for k = 0 TO 25
? k , hb_Version( k )
next k
? "-------------------------------------------------------------------"
? "Compiler used: " , hb_Version( HB_VERSION_COMPILER )
RETURN
ListBox - Simple ListBox
The following example shows how to create a simple listbox. (by Giovanni Di Maria)
PROCEDURE Main()
LOCAL GetList := {}
LOCAL cCity
SetMode( 25, 80 )
CLEAR SCREEN
cCity = "Milano"
@ 4, 4, 12, 20 GET cCity LISTBOX { "Milano", "Genova", "Roma", "Pisa", "Torino" }
READ
@ 14, 10 SAY "You have selected: " + cCity
RETURN
Documentation - Building the documentation of Harbour
You can produce the documentation of Harbour, in HTML format. You have to write some
command in a window console. (by Massimo Belgrano)
cd \harbour\examples\hbdoc
hbmk2 hbdoc.hbp
cd \harbour\doc\en
\harbour\examples\hbdoc\hbdoc -format=html
OOP, Object Oriented Programming - Rectangle CLASS
The following example shows how to create an object from a class. (by Giovanni Di Maria)
#include "hbclass.ch"
#include "inkey.ch"
// This program creates the Rectangle CLASS.
// It has the following instances:
// Top, Left, Bottom, Right, Border
// and the following methods:
// View()
// MoveRight() MoveUp() MoveLeft() MoveDown()
// Squeeze() Widen() Crush() Expand()
//--------------------------------------------------------------------//
PROCEDURE Main()
LOCAL oRect := Rectangle():New()
LOCAL nKey
SetMode( 25, 80 )
CLEAR SCREEN
oRect:Top := 5
oRect:Left := 10
oRect:Bottom := 20
oRect:Right := 70
oRect:Border := 2
DO WHILE .T.
oRect:View()
nKey = Inkey( 0 )
CLEAR SCREEN
DO CASE
CASE nKey = K_ESC
CLEAR SCREEN
RETURN .T.
CASE nKey = K_RIGHT
oRect:MoveRight()
CASE nKey = K_UP
oRect:MoveUp()
CASE nKey = K_LEFT
oRect:MoveLeft()
CASE nKey = K_DOWN
oRect:MoveDown()
CASE nKey = K_CTRL_LEFT
oRect:Squeeze()
CASE nKey = K_CTRL_RIGHT
oRect:Widen()
CASE nKey = K_CTRL_UP
oRect:Crush()
CASE nKey = K_CTRL_DOWN
oRect:Expand()
ENDCASE
ENDDO
RETURN
//--------------------------------------------------------------------//
CLASS Rectangle
DATA Top, Left, Bottom, Right, Border
METHOD View()
METHOD MoveRight()
METHOD MoveUp()
METHOD MoveLeft()
METHOD MoveDown()
METHOD Squeeze()
METHOD Widen()
METHOD Crush()
METHOD Expand()
ENDCLASS
METHOD View() CLASS Rectangle
DO CASE
CASE self:Border = 1
@ self:Top, self:Left TO self:Bottom, self:Right
CASE self:Border = 2
@ self:Top, self:Left TO self:Bottom, self:Right DOUBLE
ENDCASE
RETURN Self
METHOD MoveRight() CLASS Rectangle
self:Left ++
self:Right ++
self:View()
RETURN Self
METHOD MoveUp() CLASS Rectangle
self:Top --
self:Bottom --
self:View()
RETURN Self
METHOD MoveLeft() CLASS Rectangle
self:Left --
self:Right --
self:View()
RETURN Self
METHOD MoveDown() CLASS Rectangle
self:Top ++
self:Bottom ++
self:View()
RETURN Self
METHOD Squeeze() CLASS Rectangle
self:Right --
self:View()
RETURN Self
METHOD Widen() CLASS Rectangle
self:Right ++
self:View()
RETURN Self
METHOD Crush() CLASS Rectangle
self:Bottom --
self:View()
RETURN Self
METHOD Expand() CLASS Rectangle
self:Bottom ++
self:View()
RETURN Self
WAV files - How to play a wav file
The following example shows how to play a wav file. Compile the program with:
hbmk2 test.prg hbwin.hbc -w3. (by Giovanni Di Maria)
PROCEDURE Main()
Wapi_PlaySound( "dog.wav" )
RETURN
Debugger - How to call the debugger
The following example shows how to call the debugger. The debugger starts when the value
of variable 'a' is equal to 5. Compile the program with:
hbmk2 test.prg -w3 -b. (by Giovanni Di Maria)
PROCEDURE main()
LOCAL a, b, c, d, e
SetMode( 25, 80 )
cls
for a = 1 TO 10
b = a ^ 2
c = b * 5
d = c * 44 + 1
e = d ^ 3 + 22
IF a = 5
AltD()
ENDIF
next a
RETURN
Time - How to show a real time Clock
The following example shows how to display a real time clock, during the execution of the program.
The clock is updated continuously. Compile the program with:
hbmk2 test.prg xhb.hbc -w3. (by Giovanni Di Maria)
PROCEDURE main()
LOCAL cName, cSurname
LOCAL GetList := {}
SetMode( 25, 80 )
cls
ShowTime( 1, 70, .F. , "rg+/g" )
cName = Space( 20 )
cSurname = Space( 20 )
@ 10, 10 SAY "Name " GET cName
@ 12, 10 SAY "Surname " GET cSurname
READ
ShowTime()
RETURN
Time - How to call a function every "n" seconds
The following example shows how to call a function every "n" seconds. It works even if the
program is waiting on the menu.(by Giovanni Di Maria)
#include "inkey.ch"
PROCEDURE main()
LOCAL nOption
CLEAR SCREEN
SET KEY K_F10 TO TheBeep()
KEYSEC( K_F10, 5, - 1 )
nOption = 1
@ 10, 10 PROMPT "Option 1........."
@ 11, 10 PROMPT "Option 2........."
@ 12, 10 PROMPT "Option 3........."
@ 13, 10 PROMPT "Option 4........."
MENU TO nOption
SET KEY K_F10 TO
KEYSEC()
RETURN
PROCEDURE TheBeep()
@ 05, 70 SAY "Beep"
Tone( 1000, 2 )
@ 05, 70 SAY Space( 4 )
RETURN
Time - How to call a function at a certain time.
The following example shows how to call a function at a certain time. It works even
if the program is waiting on the menu. In this example you can
hear a long beep at 12:40:00 o'clock. (by Giovanni Di Maria)
#include "inkey.ch"
PROCEDURE main()
LOCAL nOption
CLEAR SCREEN
SET KEY K_F10 TO TheBeep()
KEYTIME( K_F10, "12:40:00" )
nOption = 1
@ 10, 10 PROMPT "Option 1........."
@ 11, 10 PROMPT "Option 2........."
@ 12, 10 PROMPT "Option 3........."
@ 13, 10 PROMPT "Option 4........."
MENU TO nOption
SET KEY K_F10 TO
KEYTIME()
RETURN
PROCEDURE TheBeep()
Tone( 2000, 18 )
RETURN
Appendix A - Photos
Appendix B - Contributors
- Giovanni Di Maria (he is still the main developer)
- Massimo Belgrano
Appendix C - What users think
- Excellent Giovanni. Great Work. Probably this is the way harbour have a good documentation. Congratulations. Bruno. (Bruno Luciani)
- Giovanni, thank you for this new tutorial... (Francesco Perillo)
- Hello Giovanni. Nice initiative. I like the C Language section. It will help beginners to start writing some C code to extend functionality or integrate a fiscal printer or other special need. Regards, Qatan. (Qatan)
- Many thanks for your great work. (Shum)
- Genial la nueva documentación, me queda mucho trabajo por hacer. gracias. great new documentation, I have much work to do. thanks. (Eugenio Silva)