---------------------------------------------------------
The Liberty Basic Newsletter - Issue #101 - October 2002
   c 2002, http://groups.yahoo.com/group/lbnews/
             All Rights Reserved
---------------------------------------------------------
---------------------------------------------------------

Ideas are like stars; you will not succeed in touching them
with your hands.  But like the seafaring [person] on the
desert of waters, you choose them as your guides, and
following them you will reach your destiny

                                     - Carl Schurz

---------------------------------------------------------
---------------------------------------------------------
In this issue:

SyntaxError: Some words from the editor
Tipcorner:   Paths and File Names
Spotlight:   Observed online - news and info
Article:     Resources for the beginner - by Brad Moore
Article:     Graphics Drawing Rules - by Alyce Watson
Article:     The beginner's guide to API and DLL calls
             - by Brad Moore
Article:     Drawing IN MEMORY - by Alyce Watson
Demo:        Radiobuttons via API - by Mike Bradbury
Demo:        NumbWord - by Rob Durk
Demo:        Working with Comboboxes - by Brad Moore
Information: About the archive
Submissions: Submit articles for publication

---------------------------------------------------------
---------------------------------------------------------

SYNTAXERROR : Some words from the editor

I am always amazed at what Carl has created here in Liberty
Basic.  It is much more than the "Little Basic that could".
We have seen in the last month several projects that people
are working on that push the envelope of the language.

Yet it is an approachable language.  A simple language that
the beginner can easily work their way into without a great
deal of trepidation.  This month the newsletter is offering
several article that span broad scope of peoples skill
levels with the language.  Of great interest to the new
comer may be the article titled "Resources for the
beginner".

I want to thank all the people who contributed to this
newsletter: Alyce Watson, Mike Bradbury and Kevin Bruce.
I also wanted to thank Brent Thorn for WMLiberty DLL which
is discussed in the API article as well as Dennis Mckinneys
example of WMLiberty which I also integrated into that 
article. 

I also want to apologize for the lateness of the release 
of this newsletter.  I hope the wait has been worth the
trouble.  Thanks  Brad Moore 

---------------------------------------------------------
---------------------------------------------------------
TIPCORNER - Paths and File Names
- by Brad Moore and Alyce Watson

I often find myself doing the same thing when I start
working with files.  I struggle to separate the path from
the filename when filedialog returns a fully qualified
filename (which it always does).  Early in September Alyce
wrote a quick little demo for someone in the Liberty Basic
community and I asked her if I could include it in the
newsletter.

I figure if I am always forgetting this and re-inventing it
each time I need it, someone else is too.  This little
snippet of a program has two short functions.  One returns
the file name and the other the path when passed a fully
qualified filename.  The trick is the `\' character in the
pathname.  Both routines search from the end of the pathname
string one character at a time looking for the backward
slash.  Once it is located the file name is all the
characters to the left of it, and the path is all the
characters to the right including the backward slash.

Simple, clean, elegant code.  Thanks Alyce for letting me
share your work.  Please use this where ever it is
appropriate.  We share it so others do not have to reinvent
it.  - Brad.


FileDialog "Select a file", "*.*", nameoffile$

Print "FileDialog returned the following: ";nameoffile$
Print
Print "Path of file is: ";SeparatePath$(nameoffile$)
Print "Filename is: ";SeparateFile$(nameoffile$)
Print
Input a$
End

Function SeparateFile$(f$)
   fileindex = Len(f$)
   filelength = Len(f$)
   While Mid$(f$, fileindex,1) <> "\"
      fileindex = fileindex - 1
   Wend
   SeparateFile$ = Right$(f$, filelength - fileindex)
End Function

Function SeparatePath$(f$)
   fileindex = Len(f$)
   While Mid$(f$, fileindex,1) <> "\"
      fileindex = fileindex - 1
   Wend
   SeparatePath$ = Left$(f$, fileindex)
End Function

---------------------------------------------------------
---------------------------------------------------------
SPOTLIGHT

Several items of interest this month on the Liberty Basic
group (hosted by YahooGroups).

The first comes from John Davidson (johnshomeport@yahoo.com)
regarding Freeform.  He writes on September 25, 2002:

"Hello All, Just a note to let you know that I have uploaded
Freeform3_08-30-2002-C  to the files section of the Freeform3
Users Group at http://groups.yahoo.com/group/FreeForm3/

If you can spare the time I would appreciate you testing it.

Please post all comments, questions and (shudder) bug reports
to the Freeform3 Users Group."

...............

The next comes from Walt Decker (lydia2hg@yahoo.com) who has
been working on interfacing Liberty Basic with a shareware
DB product called Cheetah.  He writes on August 31, 2002:

"Carl G dropped by the ABC Archives forum to thank me for supplying an
interface for the subject dll.  You are welcome Carl.

He also asked for the official word concerning these products:
Cheetah2.DLL and LBCheat.DLL.  Here is the "Official unofficial" word
concerning them:

As for an official statement about the Cheetah dll data base engine
and LBCheat.dll, there is nothing official at this time.  I am
working to supply additional LB example code and in the future
LBCheat.dll may be packaged with the Cheetah engine either for the
same price or a slightly increased price.

At this time, the LBCheat interface is free and can be obtained at
http://www.allbasiccode.com/downloads/special/special.html

The Cheetah2 database engine can be obtained at
http://www.planetsquires.com

The registered version has a price tag of $89.00 US.  A trial version
with a nag message is free.

Walt Decker
ABC Archives Admin"

You may recognize Walt's name from his work with the ABC Archives.
He is often dropping by reminding us of deadlines for getting
Liberty Basic code included into an archive.  It is a great way to
get some recognition for Liberty Basic.  If you have some code you
wish to have included please email him for details at:
lydia2hg@yahoo.com

...............

Next is a note from Eldron (egill@classicnet.net)who is marketing
a fantastic calendar product that has been created in
Liberty Basic.  It is a great place to visit to see what is
possible with Liberty Basic.  He writes on September 03, 2002:

" Hi everybody,

I have a minor update to Birthday Keeper if you want it.
It's free!  This is a full install program.

What's new?
*added frames to pictures when printed
*added printing of events....left that out the last go around
*added printing progress notice....to let you know what's going
 on on slow machines
*added heavy border to style 1 printing of calendar for cosmetic purposes
*this one uses api for all printing functions
*couple of minor bug fixes

get it here:

http://www.eaglesoartech.com/birthday.exe

good day,
Eldron"

Eldron offers the calendar as shareware, but has a standing
offer to Liberty Basic community members for free registration.
He says regarding that: "If you don't have registration number,
don't forget it's free for everyone on this list..."  You will
have to email him at his email address: egill@classicnet.net

...............

The next note is from Carl Gundel (carlg@libertybasic.com); It
regards the Liberty Basic group itself.  Carl wrote on
September 21, 2002:

"Hi all.

We just hit the file size limit in the Yahoo group and so I need to
adopt a new policy about what sorts of files we accept there.  Some
of the files are complete applications including all the Liberty
BASIC runtime files.  Others have very large image files.

I have to remove some of these files for this reason.  I may decide
to keep some files that are a few hundred K big.

Feel free to share any smaller Liberty BASIC related materials, but
if you have a complete applications, or files with very large
bitmaps, please host them on a separate website and make an
announcement in the group.

If anyone has posted large files, feel free to repost them here if
you are able to make them smaller by omitting the runtime files for
example.

Thanks!

-Carl"

So watch for some changes.  I always recommend people keep their own
viable site anyway because you never can be too sure what Yahoo's
next policy change will be.  If you are in need of a free web host
think about giving Freewebz a try.  The URL is http://www.freewebz.com

---------------------------------------------------------
---------------------------------------------------------
ARTICLE - Resources for the Beginner
          by Brad Moore (brad.moore@weyerhaeuser.com)
          copyright 2002 - all rights reserved

The new Liberty Basic programmer often has a daunting task
facing them as they try to acquire the skills to become
proficient in the use of the language.  In spite of its
simplicity, becoming a Liberty Basic programmer is not
necessarily an easy pursuit.  This is a quick reference to
help the new programmer locate the resources necessary to
better acquaint them with Liberty Basic.

Even though there are many different sources of information,
nothing takes the place of the tough work of noodling one's
way through the language.  It will take some time to get
proficient - expect that.  I offer the following ideas about
what the best steps are for the first time programmer
getting started on Liberty Basic.

1) Work your way through the tutorial that is included with
Liberty Basic.  It is the first place to start.  It is
designed in six major modules organized into weekly lessons.
They walk the new programmer through the beginning stages of
writing a program up through the final lesson where you
produce a full featured application.

2) Next there is another very good tutorial which is part of
Alyce's Mastering Liberty Basic ebook.  If you can not
afford to purchase the ebook Alyce makes her earlier version
Using Liberty Basic 2 available for free.  Both have a very
excellent tutorial that the first time programmer should
work through.

3) This is a good time to read through the Liberty Basic
command reference.  I know it seems boring, but the best way
to get to know what all Liberty Basic can and can not do it
to read each entry in the help file that describes the
commands and functions.

4) The next and final step, and this is an important one, is
to load and run each of the example programs.  Play with
them.  Change some of the commands and see what happens.
Challenge yourself to change an example program to do
something specific and then see if you can do it.

By the time you have finished these steps you will have
gained an excellent grasp of the language.  You should be
able to start a project of your own design, or leverage an
example file and expand it into something else.  To be sure
this will take some time.  Don't rush it.  Treat it as an
investment.  The skills will take you a long way.

There are several places where general information that can
be useful to the beginning (and advanced) Liberty Basic
programmer can be found.  I have compiled a brief list.


Newsletters 1 -79 (this is Alyce's archive of the early newsletters)
http://iquizme.0catch.com/lb/lb2/nl.html

Using Liberty Basic 2 (Aimed at LB 2.x, this is a free online reference)
http://iquizme.0catch.com/lb/using/index.html

Mastering Liberty Basic for LB3.02 (Recently updated, this
is the premier Liberty Basic resource for new and
established programmers - this is a shareware offering, but
is well worth the minimal purchase cost)
http://iquizme.0catch.com/lb/lbw3/master.html

Liberty Basic FAQ (a small online Frequently Asked Questions
list)
http://iquizme.0catch.com/lb/faq.html

The Official Liberty Basic group (Yahoo group)
http://groups.yahoo.com/group/libertybasic/

LB Newsletters (Yahoo group) - all of the newsletters 1 -
100 can be found here.
http://groups.yahoo.com/group/lbnews/

SAMS Teach Yourself Beginning Programming in 24 Hours -
(Greg Perry, the author of the best selling QBasic book ever
"QBasic by Example" has chosen Liberty BASIC as the
introductory programming language in his new book entitled
"SAMS Teach Yourself Beginning Programming in 24 Hours".
This book includes Liberty BASIC v2.02 and goodies from Side
by Side Software. Sams; ISBN: 0672323079; 2nd edition -
January 15, 2002)
http://www.amazon.com/exec/obidos/ASIN/0672323079/ref%3Dase%
5Fmacmillanusacom/104-7991365-5733557

Beginning Programming for Dummies 2nd Edition -
(Beginning Programming for Dummies 2nd Edition by popular
author and columnist Wallace Wang. This book presents a
general introduction using Liberty BASIC examples. The book
includes a CDROM with the shareware version of Liberty BASIC
2 and other goodies, including materials created by Side by
Side Software.  Publisher: John Wiley & Sons; ISBN:
0764508350; 2nd Bk&cdr edition (April 2001) - I hear there
is an update in the works for this one!)
http://www.amazon.com/exec/obidos/ASIN/0764508350/qid%3D1023
676813/sr%3D1-1/ref%3Dsr%5F1%5F1/104-7991365-5733557

LB3 Helpfile online (this is an online version of the
complete LB3 helpfile - you can even work your way through
the tutorials here!)
http://www.libertybasicuniversity.com/lb3docs/index.html

---------------------------------------------------------
---------------------------------------------------------
ARTICLE - Graphics Drawing Rules
     - a Liberty BASIC graphics tutorial
     - copyright 2002, Alyce Watson (alycewatson@charter.net)

BINARY RASTER OPERATIONS
The Liberty BASIC drawing rules are examples of Binary
Raster Operations, sometimes referred to as ROP2.

Each raster-operation code represents a Boolean operation in
which the values of the pixels in the selected pen and the
destination image are combined.  The manner in which they
are combined is described below.  The destination image in
this case means the graphics that are contained in a
graphicbox or graphics window at the time the drawing is
accomplished.

Here is the Liberty BASIC syntax for setting the drawing
rule:

print #handle, "rule rulename"
print #handle, "rule xor"     'as it would appear in a
program
print #handle, "rule over"    'as it would appear in a
program
or
print #handle, "rule "; _R2_NOTXORPEN 'as it would appear in
a program

This command specifies whether drawing overwrites (rulename
OVER) on the screen or uses the exclusive-OR technique
(rulename XOR).  You can also use Windows constants to
select a drawing rule (as shown above).  Note that the
Liberty BASIC named rules, OVER and XOR must be placed
within the quote marks.  If Windows constants are used for
the drawing rule command, they must be preceded by an
underscore and placed outside of the quote marks.

The most-used rules are the two named Liberty BASIC rules:
OVER and XOR.  OVER causes pixels drawn with graphics
drawing commands such as LINE, BOX or CIRCLE to appear in
the currently selected COLOR, replacing the pixels on the
screen.  XOR combines the color of the drawing pen with the
pixels on the screen using the exclusive-OR operation.  Read
below for more about using RULE XOR.

The drawing rule can be changed at any time during graphics
drawing, and affects only the graphics drawn after the rule
is changed.  The rule can be changed many times, creating an
unlimited number of interesting or unusual effects.  Look
below for an explanation of the binary raster operations,
then experiment with them in your graphics to see the
possibilities.

Here are the constants that Windows defines:

_R2_BLACK
Pixel is always 0.

_R2_COPYPEN    Liberty BASIC's rule OVER.
Pixel is the pen color.

_R2_MASKNOTPEN
Pixel is a combination of the colors common to both the
screen and the inverse of the pen.

_R2_MASKPEN
Pixel is a combination of the colors common to both the pen
and the screen.

_R2_MASKPENNOT
Pixel is a combination of the colors common to both the pen
and the inverse of the screen.

_R2_MERGENOTPEN
Pixel is a combination of the screen color and the inverse
of the pen color.

_R2_MERGEPEN
Pixel is a combination of the pen color and the screen
color.

_R2_MERGEPENNOT
Pixel is a combination of the pen color and the inverse of
the screen color.

_R2_NOP
Pixel remains unchanged.

_R2_NOT
Pixel is the inverse of the screen color.

_R2_NOTCOPYPEN
Pixel is the inverse of the pen color.

_R2_NOTMASKPEN
Pixel is the inverse of the R2_MASKPEN color.

_R2_NOTMERGEPEN
Pixel is the inverse of the R2_MERGEPEN color.

_R2_NOTXORPEN
Pixel is the inverse of the R2_XORPEN color.

_R2_WHITE
Pixel is always 1.

_R2_XORPEN Liberty BASIC's rule XOR
Pixel is a combination of the colors in the pen and in the
screen, but not in both.


RULE XOR
Rule XOR gives us a very handy ability.  It allows us to
draw graphics, then to draw them again later in the same
spot and erase them, leaving the pixels on the screen as
they were before the graphics were drawn.  Look in the
FreeForm program code that comes with Liberty BASIC.
Objects are drawn on the screen and moved about using rule
XOR.  While an object is being moved by the user, it is
drawn once to be displayed on the screen.  When the mouse
moves as the user drags the object, it is drawn a second
time at the same location to "erase" it and restore the
screen to its previous appearance.  It is then drawn in its
new location, only to be drawn again on that spot to "erase"
it when it is moved again.  This continues as long as the
object is being moved by the mouse.  When it is in the
desired position, the rule is changed back to rule OVER and
the object is drawn again, not to be erased this time.

Freeform is a large and complex program.  For a simple
example of rule XOR at work, run the following small demo
program.  It begins with some text on the screen.  When the
"Do Change" menu is clicked, graphics are drawn using rule
XOR.  Click the "Do Change" menu again, and the screen is
restored to the simple text it displayed at the start.  The
graphics have been "erased", leaving the appearance of the
screen exactly the same as it was before the drawing took
place.

Notice that when using rule XOR, drawn colors are dependent
upon the existing colors on the screen. "Red" will not
necessarily appear red.  A "red" line may change colors many
times as it passes over pixels of different colors that are
already on the screen.  Change the colors and backcolors in
the code below to see how color is affected by rule XOR.
Rule XOR is not the best choice when consistency of colors
is needed.  It is the best choice when temporary graphics
must be drawn and removed, leaving the screen appearance
unchanged.

nomainwin
UpperLeftX=100:UpperLeftY=10
WindowWidth=400:WindowHeight=440
menu #1, "&Change","&Do Change",[doChange],_
    "E&xit",[quit]
open "XOR Demo" for graphics_nsb_nf as #1
print #1, "trapclose [quit]"

'drawn with default OVER:
print #1, "down; color blue; backcolor yellow"
print #1, "fill yellow; size 5"
print #1, "place 20 140"
print #1, "font arial 20"
print #1, "\XOR Drawing Rule Demo!"

'switch to XOR:
print #1, "rule xor"
wait

[doChange]
print #1, "place 240 240"
print #1, "color red; backcolor cyan"
print #1, "circlefilled 140"

print #1, "place 10 70"
print #1, "color darkgreen; backcolor white"
print #1, "boxfilled 210 240"

print #1, "place 210 100"
print #1, "color blue; backcolor pink"
print #1, "ellipsefilled 100 125"

wait

[quit]
close #1:end

---------------------------------------------------------
---------------------------------------------------------
ARTICLE - The beginner's guide to API and DLL calls
          by Brad Moore (brad.moore@weyerhaeuser.com)
          copyright 2002 - all rights reserved

Introduction -

Although the title seems to indicate that this is a
beginners article, it is really far from it.  The beginning
programmer is not our target audience, since this person
should be primarily concerned with learning the basics of
Liberty Basic.  Leveraging the internal working of an
operating system is for the more seasoned programmer.  So
this article is intended for the intrepid Liberty Basic
programmer who, having grasped a handle of the language, is
ready to tread into the murky backwaters of the windows
operating system.

Well, it really isn't that bad.  Nothing so scary as murky
backwaters here, just the fear of the unknown.  So, lets get
on with the journey...

Before we can begin we need to get a couple terms out of the
way.  When one speaks of a DLL they are talking about a
Dynamic Linked Library.  If one were to discuss an API they
would be addressing the subject of the Application
Programmer's Interface (into Windows specifically). The
terms API and DLL are often used interchangeably, and an API
is nothing more than a very complex DLL.  I will refer to
both as a DLL henceforth.

Getting Down to Business -

Ok, a DLL is a Dynamic Linked Library, but what does that
mean?  In the simplest of terms - a DLL is no more than a
set of EXTERNAL functions that can be called by a program.

If you have been using Liberty Basic for any length of time,
then you are no doubt familiar with functions and sub
programs.  You can write your own functions using LB - as
example of what one may look like followings:

     Function Avg3(a, b, c)
          'return average of three values
          Avg3 = (a + b + c) / 3
     end function

That is a simple function. It requires three arguments
(those are the variables in between parentheses).  LB has
few variable types (actually only two: numeric and string)
so we simply understand that these are not strings (since
they don't have a $ suffix) so they are numeric.

Had I been writing this in a more strictly 'typed' language
(a language that requires I strictly follow the rules
regarding variable types and uses) I would have probably had
to declare the types of variables I was going to expect to
have passed into the function. In such a case the function
might look like this (this will not work in LB):

     Function Avg3(a as integer, b as integer, c as integer)
          'return average of three values
          Avg3 = (a + b + c) / 3
     end function

Although my program is not written in C code, a function in
a strictly typed language like C might look something like
the one above. This is important, because much of Windows is
written in C or C++. When you interface with DLLs that make

up the windows API, by calling its functions, then you must
speak its language. It expects you to declare the variables
types you are planning to pass.

There are a quite few possible variable types used passing
values to external functions that Liberty Basic supports:

Numeric Data (assign any Liberty Basic numeric variable to
any of these types)
----------------------------
double (a double float)
ulong (4 bytes) -
long (4 bytes)
short (2 bytes)
ushort, word (2 bytes)

String Data (assign any Liberty Basic string variable to
this type)
----------------------------
ptr (4 bytes, long pointer, for passing strings)

Special Purpose
----------------------------
struct (4 bytes, long pointer, for passing structs)
boolean (true/false expression)

As you can see, there are many ways to pass a numeric values
to the called routine in a DLL.  The called routine will
expect numeric data to be passed to it as a specific data
type.  You will have to investigate your DLL documentation
to know exactly how to pass the numeric value.  Passing it
wrong usually causes the program to fail.

Passing Lane Ahead -

Passing variables can get kind of messy when you want to pass 
strings.  This is the fault of C and C++ (as well as other 
languages that are similar). They do not use strings the way 
BASIC does, but rather refer to a string as an array of single
characters. Also, due to this limitation, they do not permit
a string to be passed as a string as a string, but rather as
a pointer to the memory address containing the first
character of the string. Usually these strings are
terminated (in memory) by a null character. This can get a
little confusing to the Liberty Basic programmer venturing
into the world of DLLs for the first time.


What we need to do to tell a windows function about the
string is pass a POINTER to the string. This is the value of
the memory location where the string beings in memory.
Don't forget, this string must be null terminated.  Let's
just peak into memory and see what a string looks like.

This is our null terminated string:
A$ = "Hello" + chr$(0)

Here it is represented in memory (at a fictitious memory
address):
 H       e        l        l        o       null
1001    1002     1003     1004     1005     1006

Our String is represented to a windows DLL function by its
starting address, in this case the address 1001.  If we want
to have the function work with our string we would pass a
POINTER to the starting address of our string.  This pointer
is simply a numeric value that contains the starting address
of our string (that is 1001 in our case).  We don't have to
know where our string begins in memory though, because
Liberty Basic handles that behind the scenes.  We simply
pass A$ string as a type PTR (which means pointer).

We will hit pointers again shortly, but first, I want to
make certain that the point that I have alluded to it, is
made clear. A DLL (and the API by definition) is just a set
of predefined routines that are made available to
programmers for adding functionality to their applications.
The routines are external to the programming language from
which they are called.  They are simply functions.  They
take arguments and generally return a value.  There are
many, many types of DLL and API calls. Some create windows,
some destroy windows, some handle fonts, some handle the
hardware (Com ports, Printer ports) some handle printing,
some manage the Windows central message queue, some
manipulate graphics and others allow playing of music and
video. The list goes on and on.

Open and Closed Case  -

There are two requirements in Liberty Basic that are
involved in using a DLL's function.  You must first open the
DLL for use and then you must call the function by name,
passing the correct arguments.  We have been discussing the
arguments - what they are and why they are the way the are.
We will look even further at some more advanced forms of
arguments in a few moments.  Now let us look at what we must
do to open the DLL for use.  The OPEN statement in Liberty
Basic is used to open many objects, a DLL is just one of
them.  Every DLL must be opened before a function can be
called with in.  Liberty Basic version 3.x takes care of
opening (and closing) several common DLL's that are part of
the Windows API so that you do not need to do this - the
help file calls this "Advanced DLL resolution".  These are
DLL's and their associated handles are:

       User32.dll     -  #user32     (the user DLL)

       
       Kernel32.dll   -  #kernel32   (the OS kernel DLL)
       GDI.dll        -  #gdi32      (Graphics DLL)
       Winmm.dll      -  #winmm      (Multimedia DLL)
       Shell32.dll    -  #shell32    (the OS Shell DLL)
       Comdlg32.dll   -  #comdlg32   (Common Dialog DLL)
       Comctl32.dll   -  #comctl32   (Common Controls DLL)

IF you must open a DLL file that is not part of this list
then you would use the following command syntax:

     OPEN "filename.dll" for dll as #handle

Once it is open you are permitted to call the individual
functions that are in the DLL.  Call these using the CALLDLL
command.  There is an example of this in the section that
follows.  If you opened a DLL for use in your code you must
also close it before your application terminates.  To close
a DLL file simply use the CLOSE command and pass it the
handle of the DLL to close.  Here is the official syntax of
the command:

     CLOSE #handle

Return to me  -

As you have no doubt learned in your programming experience,
Functions (in Liberty Basic) return values.  In our example
above (the function Avg3) it is understood that the return
value will be of a numeric type.  Because Liberty Basic does
not require us to be specific about the number we can return
almost anything.  A floating point value (I would expect an
average to be a floating point value), an integer, and
double precision float, etc.

Going back to our strongly typed languages (such as `C') we
are required to specify the type of value that a function
will return.  In my pseudo basic language I might write my
function something like the one below (note: this will not
run in LB):

   Function Avg3(a as integer, b as integer, c as integer)as float
        'return average of three values
        Avg3 = (a + b + c) / 3
   end function

The AS FLOAT at the end of the function specifies that the
function will return a floating point value.  Liberty Basic
requires that when a DLL is called (using the command
CALLDLL) that a value be returned.  The return value is
always passed as the last argument in the call.

If the function above were part of a DLL it would be called
using the code below (presuming the DLL had already been
opened - we will be examining this later):

     Calldll #myLib, "Avg3", _
                     a as short, _
                     b as short, _
                     c as short, _
                     r as double

So Liberty Basic expects the calling DLL to have a return
value.  There are no exceptions, unfortunately many DLL's do
not return a value of any kind.  In these case we say that
the return value is of a type VOID - meaning it is nothing.
In such a case the last parameter passed would be something
like `Result as void'.  Using this special variable type
(you can only use it for a return value) tells Liberty Basic
that the DLL does not pass a return value back.  It is
important to know the DLL call and the arguments and return
values.  You can not specify a return type of VOID simply
because you do not know what it returns.  You must know and
you must declare it correctly.

A Pointer or Two -

Two different variable types pass pointers.  They are PTR
(used to pass a string) and STRUCT (used to pass a
structure).  It is highly inefficient for a program to pass
whole arrays of data to external functions.  This would take
up large amounts of memory (in addition to the memory they
currently occupy) and would slow down the program.  In
response to this problem most languages pass and return a
pointer to the array and not the entire array.

The workings of a pointer are both simple and confusing.  To
understand them we have to understand how memory is managed.
In our computer we have a vast bank of small storage
compartments.  I like to think of these as little mail
boxes, kind of like the ones you would see in older hotels
behind the front desk.  Row after row of little boxes, some
with notes in them, some with keys in them and some are
empty.  If we continue the analogy we would notice that each
of these little compartments is numbered consecutively and
in our computer they are either empty or contain a single
number.  The number represents a variable, either a
character or a numeric.  (Technical Note: because LB uses
floating point values for all numbers - more than one of the
little boxes is required to store the number.  For the
purposes of this discussion we will ignore this fact and
treat them as if can neatly fit into a single box.)

An array or a string (remember that a string is simply an
array of characters) is said to occupy several consecutive
boxes.  The first element (or character) is in the first box
and the second in the second and so on.

+---+---+---+---+---+---+---+---+---+---+
|   |   |   |   | H | e | l | l | o |   |
+---+---+---+---+---+---+---+---+---+---+
  1   2   3   4   5   6   7   8   9   10
+---+---+---+---+---+---+---+---+---+---+
| w | o | r | l | d |   |   |   |   |   |
+---+---+---+---+---+---+---+---+---+---+
  11  12  13  14  15  16  17  18  19  20

The example above shows these hotel mailbox (or pidgin hole)
style boxes with the string "Hello world" placed in it.  It
was placed there with the following line of code:

     MyString$ = "Hello world"

The string starts at box number 5 - we call box 5 the memory
address of the string.  This is a simple representation of
memory.   In real life we don't get to choose the memory
locations of our variables, and we don't even care what the
memory location they are in.   This is all managed for us.
What we do care about is being able to pass the location
where an array begins.  This is the job of the pointer.
Pointers do not have a great deal of use in the core
language of Liberty Basic.  We would not say that variable
`A' is a pointer as we would were we programming in C++.
The only usage of this value is as an argument to a DLL
call.

     MyString$ as PTR.

The PTR tells Liberty Basic that I do not want the value of
the string, just the address.  That is 5 in this case.  The
called DLL will be able to receive this value and go look at
that location in memory (the very same location we wrote to
when we placed "Hello world" into memory) and use and even
alter the variable.  Well, I am sure that is clear as mud.
It is not necessary to fully understand the dynamics of the
pointer to use the pointer, but it helps to know to a degree
what is going on.

Getting Structured  -

 Pointers to strings have been discussed, but there is also
another pointer type called a STRUCT.  Many languages
support formations such as Structs.  They are sometimes call
use defined variable types or in other cases structures.
They are simple records of multiple variable types
(elements) that are bound together.  Some languages let you
define the type and then create multiple variables of that
type.  For instance the user defined type EMPLOYEE contains
the following elements:

     Name
     Identification Number
     Start Date
     End Date
     
Each of these elements are of a specific data type.  The one
named Name is a string.  Identification Number could be a
long integer.   In Liberty Basic we must declare the data
types for each element as we define the element name.  We
also must give the struct a name.  The example above might
look like the following if we were to define it in Liberty
Basic code:

     Struct Employee,
            Name as string, _
            Identifacation_Num as integer, _
            Start_Date as char[10], _
            End_Date as char[10]

The valid data types that can be declared are very similar
to those used when passing variables to DLL's as arguments.
One of the interesting items to note is that a struct can
contain another struct as shown by the list.  Also a unique
variable type is available in this list that can not be used
in calling DLL's, and that is the type CHAR.  It is used to
define fixed length strings.  The example above used CHAR to
define the date elements as a 10 character string.

Additional 
characters can not be stored in this variable.
Obviously the length of the fixed length string is specified
by the value between the square brackets.  Also note in the
list below that you may not use the variable type VOID in a
struct, as it has no meaning in this context.  Here is the
list of valid types:

Numeric Data (assign any Liberty Basic numeric variable to
any of these types)
----------------------------
double (a double float)
ulong (4 bytes) -
long (4 bytes)
short (2 bytes)
ushort, word (2 bytes)

String Data (assign any Liberty Basic string variable to
this type)
----------------------------
ptr (4 bytes, long pointer, for passing strings)
char (2 byte charater)
char[n] (4 byte pointer to fixed length string - specify
length as value n)

Special Purpose
----------------------------
struct (4 bytes, long pointer, for passing structs)
boolean (true/false expression)


Liberty Basic's treatment of structs (user defined data
types) differs from many languages.  Most languages require
the programmer to first define the data type and then
declare variables of that type.  In this way you could have
multiple instances of variables of the type EMPLOYEE.
Liberty Basic combines the type creation and variable
creation together as a single step.  The date type
definition is the variable, and there can only be ONE
instance of that variable.

User defined variable types are powerful (especially in
database programming) and add significant utility to a
language.  Carl has said he will be looking into enhancing
Liberty Basic to allow multiple instances of a struct
(instead of just the one by definition).  This will be a
welcome addition.

Structs can be used both by the Liberty Basic core language
and in calling DLLs for passing and receiving complex data
structures.  The single instance limitation does not give
them as much utility in the core language, but they are
indispensable in use with DLLs.  Take for instance the call
to get the window dimensions of a window.  It gets the
various dimensions returned in the form of a struct (data
record).

     CallDLL #user32, "GetWindowRect", hwnW As long, _
                                  winrec As struct, _
                                  result As long

Here is the definition of that struct that is used in the
DLL call above:

     Struct winrec, x1 As long, y1 As long, x2 As long, y2
     As long

It is a record called "winrec" consisting of four values all
of which are long integers.  This record is stored in memory
in much the same way an array will be stored - each data
element in consecutive memory locations.  Since the language
has no way of knowing what the contents, size or make up of
a struct will be, it is difficult to pass these as whole
entities.  Luckily, since they are stored in consecutive
memory locations this is not necessary.  All that needs to
be passed is the beginning memory location of where the
struct starts in memory.  Again this is a pointer.  It
points to a memory location.

As I mentioned, the Struct command is useful in calling
DLL's and also for use with the core language.  There are
several cases where one might intentionally use a struct in
the course of programming without ever calling a DLL.  The
most obvious one to me currently is to supplement the lack
of globals by creating a global struct to hold all of your
global values.  It might look like this:

     Struct global, _
            Name as string, _
            Date as string, _
            Counter as integer

These could be accessed, changed and utilized through out
the program since (as I recently learned) structs are global
in scope.

To set a value, or access a value in the struct we use the
following command syntax:  struct_name.element.STRUCT.  The
word "STRUCT" in the syntax is the keyword that defines the
variable as an element of a struct.  Below is a couple
example of code that assigns a value to a element in the
global struct mentioned above - also shown is the code to
print an element from the same struct.
     
     global.Name.struct = "Brad"
     Print global.Counter.struct
     
There are a couple special functions that are used in
conjunction with structs.  The first is used to retrieve the
contents of a memory location pointed to by an element of
the struct.  In the struct above if, after assigning "Brad"
to the Name element, we simple printed the Name element we
would get a number.  It is the memory location where the
string Name is stored.  A pointer again.  To print the value
of the string (or otherwise retrieve it) we need to use the
function Winstring.  Winstring requires a pointer as its
argument.  According to the help file it:

".returns a string when a function returns a pointer to a
string.  This function is especially useful when retrieving
the text string from a STRUCT that has been altered by a
function."  Using that function we could print the value
pointed to by the element Name in the global struct.  Here
is that code:

     Print winstring(global.Name.struct)
     
Another useful technique is determining the length (size) of
a struct using the LEN() function.  This is most often used
in conjunction with calling a DLL where the DLL requires the
length (size) of the struct that is being passed.  The
following assigns the size of the Employee struct (mentioned
earlier) to the variable sizeofstruct:

     sizeofsrtuct =  len(Employee.struct)

Beyond the Basics -

Structs offer a great deal of power to the programmer and
have opened up many possibilities in the realm of calling
DLL's.  Even more recent and powerful feature is the
callback.  I will touch on this feature just briefly, as a
whole tutorial can be written about callbacks alone.  They
are by far the most complex area of DLL interface in Liberty
Basic, but with the complexity comes immense power.

DLL's sometimes require a callback function to be passed to
them in the call.  This is an address in memory of a
specific function that can be triggered by the DLL when an
event is fired.  The function is a regular Liberty Basic
function.  To setup a callback you must specify it (using
the command Callback), before you invoke the DLL call that
will require the callback.  According to the help file the
syntax is as follows:

     callback addressPTR, functionName(type1, type2...),
     returnValue
     
     Usage:
     
     addressPTR - assigns a name to the memory address of
     the function.
     
     functionName - is the name of the function in the
     Liberty BASIC program that will be called by the API
     function.
     
     (type1, type2...) - a comma-separated list of
     parameters, which will be specific to the function
     used.  The parameters must be valid data TYPES such as


     "ulong" and "long".
     
     returnValue - the type of return value is listed after
     the closing parenthesis.  The Liberty BASIC function
     may return a value to the calling function.
     
The way this works is that the DLL is passed the addressPTR
which points to a function that appears elsewhere in your
code.  The helpfile has an example I recommend you look at
if this is an area that interests you.  It demonstrates the
DLL call enumwindows which returns a callback to the calling
program.  Also of interest and great utility is a DLL
written by Brent Thorn called WMLiberty.dll (get it at
http://groups.yahoo.com/group/lbexp/files/).  It utilizes
the callback capability of Liberty Basic to trap messages in
the windows message queue and to trigger events in Liberty
Basic based on those messages.  The function is more complex
than I intend to go into, but for the advanced Liberty Basic
programmer looking to integrate advanced functions (such as
MDI, Key Capture, Control Subclassing) into your
applications this is the tool you are looking for.

Dennis Mckinney" (dlm81854@accs.net) recently supplied an
example of a callback being used to detect
the movement or resizing of a window.   This example uses
WMLiberty.dll to setup the callback that triggers the event
handler.

     '-- code --
         nomainwin
     
         Open "WMLiberty.dll" For DLL As #wmlib
     
         open "Test Size / Move Message" for window as #1
         print#1, "trapclose [quit]"
         hWin = hwnd(#1)
         hWin(0) = hWin
         Callback lpfnOnMove,OnMove(long,long,long,long),long
         CallDLL #wmlib, "SetWMHandler", _
                         hWin As long, _
                         _WM_EXITSIZEMOVE As _
                         long, _
                         lpfnOnMove As long, _
                         0 As long, _
                         ret As long
     
     [loop]
         Scan
     GoTo [loop]
     
     [quit]
         close #1
         close #wmlib
         end
     
     Function OnMove( hWnd, uMsg, wParam, lParam )
         If uMsg = _WM_EXITSIZEMOVE AND hWnd = hWin(0) then
             Notice "Window Moved or Resized"
         End If
     End Function


Final Words -

So what I have covered is the dynamics of calling DLL
functions from Liberty Basic.  I have merely scratched the
surface of the material.  There is much more to learn.
There is one aspect of call the DLL that I have not covered,
and it is perhaps one of the more difficult areas of
understanding, and that is converting the call (which is
often documented in C or C++) to Liberty Basic format.  This
is another subject that could easily consume another
article.  The foundation has been laid here.  I would
welcome someone of greater experience who would write about
this.  For now let me point you to a few resources that you
can use in at least understanding the Windows API calls.

Alyce Watson has written a marvelous ebook called Mastering
Liberty Basic.  The new update for Liberty Basic 3.02 has
just been released.  It can be downloaded from the website
"Alyce's Restaurant" at http://iquizme.0catch.com/lb/ - it
is shareware, but is hands down the best, most authoritative
resource for Liberty Basic around.

There are several free sources of help files that cover the
Windows API for the programmer.  Alyce has links to many of
these on her website at
http://iquizme.0catch.com/lb/api/index.html .  There you
will find the file Win32api.zip - a downloadable reference.
Another excellent source of information is the Windows 32
SDK by Borland - it can be downloaded from
ftp://ftp.inprise.com/pub/bcppbuilder/techpubs/bcbhlp01.zip
.  A great website called All API Net
(http://www.allapi.net/ ) contains references to hundreds of
API calls all formatted for Visual Basic.  It also contains
an API viewer you can download.  Don't forget that Microsoft
has references to the API calls also at its developers
support site called the MDDN - you will have to dig a bit,
but this link will get you started:
http://www.microsoft.com/msdownload/platformsdk/sdkupdate/

I personally use a reference book which explains the Windows
32bit API and offers examples in Visual Basic 5.  It is
called Visual Basic 5.0 programmers guide to the WIN32 API
by Danny Appleman.  I recently checked Amazon.com and found
that there is a new release of this book called  Visual
Basic Programmer's Guide to the Win32 API, Published by Sams
- ISBN: 0672315904

---------------------------------------------------------
---------------------------------------------------------
ARTICLE - DRAWING IN MEMORY
     - an intermediate-advanced graphics tutorial
     - copyright 2002, Alyce Watson

It is not currently possible to draw on a hidden graphicbox,
then transfer the image from the hidden graphicbox to a
visible graphicbox.  If it were possible, it would be
achieved by using GETBMP on the hidden graphicbox to get a
named Liberty BASIC bitmap, then using DRAWBMP on that named
bitmap to draw it into the visible box.  Since this will not
work, the alternative is to use GDI functions to do the
drawing in memory.

Drawing with the Graphics Device Interface (GDI) is a
subject that would easily fill an entire book.  This
tutorial is NOT a tutorial on drawing with GDI.  It presents
a method to draw in memory, then place the image on the
screen in Liberty BASIC.  It doesn't attempt to explain the
individual GDI drawing functions.

It is assumed that the reader understands the fundamentals
of making Windows API calls.  For more information on making
API calls, and for using GDI functions, please examine one
of the many Windows API reference books that are available
in libraries and bookstores, or check the Microsoft
Developers Network Library here:

http://msdn.microsoft.com/library

You may also check my website and electronic books:

http://iquizme.0catch.com/lb/
http://iquizme.0catch.com/lb/lbw3/master.html
http://iquizme.0catch.com/lb/using/index.html


THE DEVICE CONTEXT
GDI doesn't draw on a window, it draws on a device context
(DC).  A DC is an interface used by GDI so that Windows can
draw on any of the variety of hardware that might be
installed on a computer.  Windows can also draw on a memory
device context, and that is what we'll use for this method.


MEMORY DRAWING - STEP BY STEP
Here is an outline of the steps we'll be using.

- create a window with a graphicbox
- put the pen DOWN in the graphicbox
- use GetBmp to get a Liberty BASIC bitmap from the
  graphicbox
- obtain the handle of the graphicbox with the hwnd()
  function
- obtain the handle of the Liberty BASIC bitmap with the
  hbmp() function
- get a DC for the graphicbox with GetDC
- create a memory DC with CreateCompatibleDC
- select the LB bitmap into the memory DC with SelectObject
- issue GDI drawing commands to the memory DC
- select the default bitmap back into the memory DC, freeing
  the LB bitmap
- use DRAWBMP to display the bitmap in the graphicbox -
  flushing if desired
- as many times as needed, select the bitmap into the memory
  DC, draw on it with GDI functions, deselect it from the
  memory DC and display with DRAWBMP

When the program ends:
- delete the created DC with DeleteDC
- release the graphicbox DC with ReleaseDC
- delete the LB bitmap with UNLOADBMP


MEMORY DRAWING - THE THEORY
Using the GETBMP command allows us to get a named, Liberty
BASIC bitmap that we can display with DRAWBMP or save with
BMPSAVE.  We can get a Windows handle to this bitmap with
the HBMP() function.  Once we have a Windows handle, we can
select the bitmap into a memory device context and use GDI
functions to draw on it.  After deselecting the LB bitmap
out of the memory device context, we can draw the altered
bitmap in our graphicbox with DRAWBMP or we can save it to
disk with BMPSAVE.


USING GDI - THE DISADVANTAGES
The most obvious disadvantage of drawing with GDI rather
than using Liberty BASIC's own drawing commands is that the
API drawing functions are more complicated, and they require
device contexts to be gotten, created, released and
destroyed.  Using GDI also requires that pens, brushes and
fonts be created, selected into the device context, and
destroyed when they are no longer needed.


USING GDI - THE ADVANTAGES
Using GDI functions allows us to draw in memory, which
presents many possibilities, such as flicker-free animation,
and the ability to draw many objects before allowing the
user to view them.  In other words, the drawings can be
presented as a finished picture, and the user doesn't see
each step as it is drawn.  There is one other big advantage
to using GDI functions.  There are many more graphics
possibilities with GDI functions than with Liberty BASIC
drawing commands.  There are functions to floodfill, to
create other objects such as arcs and round rectangles, to
draw text that is filled with patterns, to draw with
different RASTER OPERATIONS (this is how sprites are done)
and on and on.


DRAWING IN MEMORY - A SIMPLE SAMPLE
The following code will run in Liberty BASIC 3.x.  It is
well commented.



nomainwin

'graphicbox size includes borders,
'so requires 202x202 graphicbox to
'display a drawing area 200x200
graphicbox #1.g, 10,10,202,202

open "Memory Drawing" for window_nf as #1
#1 "trapclose [quit]"
#1.g "down"

'use getbmp to get an LB bitmap
#1.g "getbmp mem 0 0 200 200"

h=hwnd(#1.g)    'handle of graphicbox
hMem=hbmp("mem")'handle of LB bitmap

'get a device context for graphicbox
CallDLL #user32, "GetDC",_
h As long,_ 'handle of graphicbox
hDC As long 'returns device context

'create a device context in memory
'that has the same attributes as the
'device context for the graphicbox
CallDLL #gdi32,"CreateCompatibleDC",_
hDC As long,_   'device context of graphicbox
memDC As long   'returns memory device context

'select the LB bitmap into the
'memory device context
CallDLL #gdi32,"SelectObject",_
memDC As long,_     'handle of memory DC
hMem As long,_      'handle of LB bitmap
oldObject As long   'returns handle of previous
                    'bitmap in DC

'draw some graphics with GDI functions:
CallDLL #gdi32, "Rectangle",_
memDC As long,_     'memory DC
10 As long,_        'upper left x
10 As long,_        'upper left y
60 As long,_        'lower right x
80 As long,_        'lower right y
r As boolean

'next call requires this struct
struct Point, x as long, y as long

'same as LB's PLACE command
CallDLL #gdi32, "MoveToEx",_
memDC As long,_     'memory DC
40 As long,_        'x
20 As long,_        'y
Point As struct,_   'returns previous x and y
r As boolean

'same as LB's GOTO command
CallDLL #gdi32, "LineTo",_
memDC As long,_     'memory DC
140 As long,_       'x
70 As long,_        'y
r As boolean

'fill a string variable
t$="Memory Drawing"

'get length of variable
ln=len(t$)

'draw the text
CallDLL #gdi32, "TextOutA",_
memDC As long,_     'memory DC
10 As long,_        'x location
130 As long,_       'y location
t$ As ptr,_         'string of text
ln As long,_        'length of string
r As long

'you must deselect the bitmap from
'the memory DC each time you want to
'display it with DRAWBMP
'
'select the previous bitmap back
'into the memory DC to do this
CallDLL #gdi32,"SelectObject",_
memDC As long,_     'memory DC
oldObject As long,_ 'original bmp in memDC
hMem As long        'returns bmp to deselect

'now, simply draw it with DRAWBMP
'and flush
#1.g "drawbmp mem 0 0; flush"

wait

[quit]
'be sure to unload the bmp
unloadbmp "mem"

'release the DC for the graphicbox
CallDLL#user32,"ReleaseDC",_
h As long,_     'graphicbox handle
hDC As long,_   'DC handle
result As long

'delete the memory DC from memory
CallDLL #gdi32, "DeleteDC",_
memDC As long,_ 'memory DC handle
r As boolean

close #1:end

---------------------------------------------------------
---------------------------------------------------------
Demo - API Radiobuttons - by Mike Bradbury, Stoke-on-Trent,
England
mike@karemi.fsnet.co.uk


Here is how Mike introduces his Liberty Basic demo showing
Radiobuttons created both by LB and using API calls:

This code is for LB3, tested with WIN98SE/LB3.02
Submitted for Newsletter inclusion by Mike Bradbury.


Programmers sometimes need buttons to have a variety of
appearances, depending upon the function of the button.
Liberty BASIC native code limits the type and style of
button available.  Included here is code to generate six
different radiobutton styles plus the standard LB style.  
The groupbox style can also be changed (see comment within 
the code).  A control of class BUTTON can be given a style 
of BS_AUTORADIOBUTTON and BS_PUSHLIKE for standard button
appearance. Omitting the BS_PUSHLIKE style gives the
standard radiobutton appearance.  Regular buttons can also 
be given the same styles, just omit the style
BS_AUTORADIOBUTTON to draw a standard (non radiobutton)
button.

Here is Mike's Code.  You can find a BAS that you can
experiment with in the archive attached to the newsletter.
I noticed that there seems to be a lot of lines wrapped in
the newsletter version, so you are going to want to run the
bas file in the archive.  Thanks.

...............

 `--Radiobutton Demo by Mike Bradbury - for Liberty Basic

'Check that the user has version 3 of LibertyBASIC, if not
then end program execution.
If Val(Left$(Version$,1))<>3 Then
            Notice "Sorry, LB version 3 only."
            End
End If

'Dim arrays for control handles
Dim hC(5)
Dim hr(6)

'set up window and standard LB controls
WindowWidth=450:WindowHeight=500
UpperLeftX=200:UpperLeftY=200

NoMainWin
Button #w.1, "",[rb1],UL,0,0,0,0 'these buttons are hidden
                                 and linked to
Button #w.2, "",[rb2],UL,0,0,0,0 'the api generated buttons
                                 for event handling
Button #w.3, "",[rb3],UL,0,0,0,0 'Although 25 radiobuttons
                                 are drawn, there are
Button #w.4, "",[rb4],UL,0,0,0,0 'only 5 branch labels (rb1
                                 to rb5).Each row of
Button #w.5, "",[rb5],UL,0,0,0,0 'radiobuttons have the same
                                 function but different styles.

'this sets up that five standard LB radio buttons
Groupbox #w.gb1, "LB Radiobuttons with flat
groupbox",42,390,365,50
Radiobutton #w.rb1, "LBRB1",[rb1],UL,55,410,60,20
Radiobutton #w.rb2, "LBRB2",[rb2],UL,125,410,60,20
Radiobutton #w.rb3, "LBRB3",[rb3],UL,195,410,60,20
Radiobutton #w.rb4, "LBRB4",[rb4],UL,265,410,60,20
Radiobutton #w.rb5, "LBRB5",[rb5],UL,335,410,60,20

Open "Radiobutton & Groupbox styles." For Window_nf As #w
#w, "trapclose [quit]"

'get the handle of the window
h=hWnd(#w)

'get handles of hidden LB buttons
hC(1)=hWnd(#w.1)
hC(2)=hWnd(#w.2)
hC(3)=hWnd(#w.3)
hC(4)=hWnd(#w.4)
hC(5)=hWnd(#w.5)

'set font for window and statictext control
#w, "font arial 8"

'create font1 for api generated controls
    fontname$ = "Arial" + Chr$(0)
    fontheight = 14
    CallDLL #gdi32, "CreateFontA",_
         fontheight As long,_
         0 As long,0 As long,0 As long,_
         0 As long,0 As long,0 As long,_
         0 As long,0 As long,0 As long,_
         0 As long,0 As long,0 As long,_
         fontname$ As ptr,_
         hFont1 As long

'create font2  for api generated controls
    fontname$ = "arial" + Chr$(0)
    fontheight = 16
    CallDLL #gdi32, "CreateFontA",_
         fontheight As long,_
         0 As long,0 As long,0 As long,_
         0 As long,0 As long,0 As long,_
         0 As long,0 As long,0 As long,_
         0 As long,0 As long,0 As long,_
         fontname$ As ptr,_
         hFont2 As long

'make raised groupbox with empty string for caption
class$="BUTTON"
'this sets up the style for the groupbox
gboxstyle=_WS_CHILDWINDOW OR _WS_VISIBLE  or _BS_GROUPBOX

'set the size of the groupbox
gboxX=42
gboxY=10
gboxW=365
gboxH=365

'these two sets of calls create the groupbox
    CallDLL #user32, "GetWindowLongA", _
                      h As long, _
                      _GWL_HINSTANCE As long, _
                      hInst As long
    gbStyle=1 'groupbox style 1=raised, 0=flat
    CallDLL #user32, "CreateWindowExA",_
                     gbStyle As long, _
                     class$ As ptr,_
                     "" As ptr, _
                     gboxstyle As long, _
                     gboxX As long, _
                     gboxY As long, _
                     gboxW As long, _
                     gboxH As long,_
                     h As long, _
                     0 As long, _
                     hInst As long, _
                     0 As long, _ 
                     hGrb As long

'change font for groupbox control to the font that was
created in the api calls above
    CallDLL #user32,  "SendMessageA",_
                       hGrb As long,_    'handle
                       _WM_SETFONT As word, _
                       hFont2 As long, _
                       1 As long, _
                       result As void

'set captions for groupbox
res=setText(hGrb,"RadioButton styles with raised groupbox")

'make buttons in different styles, omit legends till font
has been changed 
'Text position on control can be set with style
BS_RIGHT/BS_LEFT/BS_CENTER/BS_TOP/BS_BOTTOM

 WARNING THESE LINES ARE WRAPPED 

'Radiobuttons 1 to 5
bstyle(1)=_WS_CHILDWINDOW OR _WS_VISIBLE  or _BS_PUSHLIKE or
_BS_AUTORADIOBUTTON or _BS_LEFT
'Radiobuttons 6 to 10
bstyle(2)=_WS_CHILDWINDOW OR _WS_VISIBLE  or _BS_PUSHLIKE or
_BS_AUTORADIOBUTTON or _BS_FLAT
'Radiobuttons 11 to 15
bstyle(3)=_WS_CHILDWINDOW OR _WS_VISIBLE  or _BS_PUSHLIKE or
_BS_AUTORADIOBUTTON or _BS_RIGHT
'Radiobuttons 16 to 20
bstyle(4)=_WS_CHILDWINDOW OR _WS_VISIBLE  or _BS_PUSHLIKE or
_BS_AUTORADIOBUTTON or _BS_FLAT
'Radiobuttons 21 to 25
bstyle(5)=_WS_CHILDWINDOW OR _WS_VISIBLE or
_BS_AUTORADIOBUTTON or _BS_TOP
'Radiobuttons 26 to 30
bstyle(6)=_WS_CHILDWINDOW OR _WS_VISIBLE or
_BS_AUTORADIOBUTTON or _BS_RIGHTBUTTON or_
          _BS_MULTILINE or _BS_BOTTOM or _BS_CENTER

'Set the starting positions and sizes for buttons
yOrg=35
bheight=25
count=1

'loop through creation of buttons
For row=1 to 6 'six rows of buttons, each row having a
different style
   xOrg=55
   For n=1 to 5   'five buttons in each row
      'draw buttons and return handle of api button in one function
       hr(n) = _
drawButton(h,hC(n),row,class$,"",bstyle(row),xOrg,yOrg,60,bheight)
      xOrg=xOrg+70
   Next n
   'set font & captions for controls
   For n=1 to 5
     hCont=hr(n)
     CallDLL #user32,  "SendMessageA",_
                        hCont As long,_    'handle
                        _WM_SETFONT As word, _
                        hFont1 As long, _
                        1 As long, _
                        result As void
     legend$="RB"+Str$(count)
     If count>25 Then legend$=legend$+" ABC"
     res=setText(hr(n),legend$)
     count=count+1
   Next n
   yOrg=yOrg+55
   If count=26 Then bheight=35
Next row

'this completes the drawing of the window - wait for user input
Wait

'-----------------------------------------------------------
'  code to support triggered events

[rb1]
Notice "Left button clicked"
Wait

[rb2]
Wait

[rb3]
Wait

[rb4]
Wait

[rb5]
Notice "Right button clicked"
Wait


[quit]
    'remove fonts from memory
    CallDLL #gdi32, "DeleteObject", hFont1 As long, r As boolean
    CallDLL #gdi32, "DeleteObject", hFont2 As long, r As boolean
    Close #w
    End

'-----------------------------------------------------------
'  called functions

Function drawButton(hW,hB,p,class$,text$,style,x,y,w,h)
    'this function is the heart of the process.  It draws the
    'raidiobutton and returns the handle to the button

    'get instance handle of window
    CallDLL #user32, "GetWindowLongA", _
                     hW As long, _
                     _GWL_HINSTANCE As long, _
                     hInst As long

    'create button of specified style and get handle of button
    Select Case p
       Case 1,2,5,6: pro=1
       Case Else pro=0
    End Select

    'CreateWindowExA actually creates the control (a radiobutton)
    CallDLL #user32, "CreateWindowExA", _
                     pro As long, _
                     class$ As ptr,_
                     text$ As ptr, _
                     style As long, _
                     x As long, _
                     y As long, _
                     w As long, _
                     h As long,_
                     hW As long, _
                     0 As long, _
                     hInst As long, _
                     0 As long, _
                     hButton As long

    'get ID of hidden LB button
    CallDLL #user32, "GetWindowLongA", _
                     hB As long, _
                     _GWL_ID As long, _
                     bID As long

    'link clicked button with event for hidden button
    CallDLL #user32, "SetWindowLongA", _
                     hButton As long, _
                     _GWL_ID As long, _
                     bID As long,_
                     res As long

    'return the button handle
    drawButton=hButton
End Function

Function setText(h, caption$)
   CallDLL #user32, "SetWindowTextA", _
                     h As long, _        'handle
                     caption$ As ptr, _  'new string
                     result As void
End Function



---------------------------------------------------------
---------------------------------------------------------
Demo - NumbWord by Rob Durk

This demo will parse a number into segments, then assemble
an English text version of the number.  For instance the
number 121 would be returned as One hundred and twenty one.
This would be a useful routine in a check book program, and
other places as well.  I added a couple comments and
standardized a couple IF statements as well as putting the
execution into a loop so that you can convert as many
numbers as you would like.  There is a bas file attached in
the archive.  Thanks Rob!

'#############################################
'#                  NumbWord                 #
'#      (my, what an imaginative name!)      #
'#                by Rob Durk                #
'#          12th/13th September 2002         #
'# Version 2 - parsing done in a single loop #
'#    (comments and input loop - B.Moore)    #
'#############################################

[numbword.start]
    Dim title$(1)
    title$(1)="NumbWord 2"

    num$ = "##"


[get.input]
    Print "Type in the number you wish to convert (zero to quit):";
    Input num$
    num$=Trim$(num$)
    If num$ = "0" Then GoTo [numbword.end]
    'make sure result$ is cleared
    result$ = ""

    'dispose of anything after a decimal point...
    If Int(Val(num$))<>Val(num$) Then
        Call MsgWin "Don't do bitty numbers, sorry!"
        num$=Str$(Int(Val(num$)))
    End If

    num.len=Len(num$) 'we get this AFTER any line which
                      might trim the length of num$

    'make sure no non-numeric characters are in there
    If Str$(Val(num$))<>num$ Then
        Call MsgWin "Sorry, can't make sense of that.."
        GoTo [numbword.end]
    End If

    'sorry, you're limited to numbers less than 1
    quadrillion - how lazy I am!
    If num.len>15 Then
        Call MsgWin "Gosh!!"+Chr$(13)+ _
                    "I'm not clever enough to count that high.."
        GoTo [numbword.end]
    End If


[divide.into.3s]
'expand string to be an exact multiple of 3 in length
'This is the logical break for numbers, 100's 100,000's
100,000,000's etc
    num.tmp=num.len-(3*(Int(num.len/3)))
    If num.tmp<>0 Then num$=Right$("000"+num$,(3-num.tmp+num.len))
    num.len=Len(num$)
    num.group=Int(num.len/3)

'make arrays to hold the groups of 3
    Dim group$(num.group)
    Dim numbword$(num.group)

'divide (and conquer) the input into 3s
    For loop=1 to num.group
        group$(loop)=Mid$(num$,((loop-1)*3)+1,3)
    Next loop


[parse.3s]
'parse each group of 3
    For loop=num.group to 1 step -1

[1st.digit]
    If Val(Left$(group$(loop),1))<1 Then GoTo [2nd.digit]
    numbword$(loop)= _
       Word$("one two three four five six seven eight nine", _
       Val(Left$(group$(loop),1)))+" hundred"
    If Val(Right$(group$(loop),2))>0 Then
numbword$(loop)=numbword$(loop)+" and"

[2nd.digit]
    If Val(Mid$(group$(loop),2,1))<1 Then GoTo [3rd.digit]
    If Val(Right$(group$(loop),2))<20 Then GoTo [those.awkward.teen.years]
    numbword$(loop)=numbword$(loop)+" "+ _
        Word$("ten twenty thirty forty fifty sixty seventy "+ _
        "eighty ninety",Val(Mid$(group$(loop),2,1)))

[3rd.digit]
    If Val(Right$(group$(loop),1))<1 Then GoTo [next.group]
    numbword$(loop)=numbword$(loop)+" "+ _
            Word$("one two three four five six seven eight nine", _
            Val(Right$(group$(loop),1)))
    GoTo [next.group]

[those.awkward.teen.years]
    If Val(num$)>Val(group$(loop)) and _
        Val(Left$(group$(loop),1))<1 and loop=num.group Then _
        numbword$(loop)=numbword$(loop)+" and"
    numbword$(loop)=numbword$(loop)+" "+ _
        Word$("ten eleven twelve thirteen fourteen fifteen "+ _
        "sixteen seventeen eighteen nineteen", _
        (Val(Right$(group$(loop),2))-9))

[next.group]
    Next loop


'dimension an array for the multipliers
    Dim multiply$(5) 'maximum value of num.group (=max
                     length of numeric input/3)

'multiply$(arrayindex)=name of multiplier equalling
10^((arrayindex-1)*3) - add commas if you like them..

        multiply$(5)=" trillion"   '10^12
        multiply$(4)=" billion"    '10^9
        multiply$(3)=" million"    '10^6
        multiply$(2)=" thousand"   '10^3
        multiply$(1)=""            '10^0 =1, thus has no multiplier


'tag multipliers to groups with a value
    For loop=1 to num.group
        If Trim$(numbword$(loop))<>"" Then _
             numbword$(loop)=numbword$(loop)+ _
             multiply$(num.group-loop+1)
    Next loop


'stitch it all together
    For loop=1 to num.group
        result$=result$+Trim$(numbword$(loop))+" "
    Next loop

'tadaa!
    Print "You typed ";Trim$(result$)
    goto [get.input]


[numbword.end]
    End


' sub - MsgWin
Sub MsgWin msg$
    Notice "Message from "+title$(1)+Chr$(13)+msg$
    End Sub

---------------------------------------------------------
---------------------------------------------------------
Demo - Working with Comboboxes
by Brad Moore

This demo is the result of a thread on the Liberty Basic
group that dealt with reseting the combobox back to a blank
value after the list has been pulled down once.  Usually
once a value list has been viewed the list will display one
of the value on the value list, and unless blank is one of
the possible values (we did not want it to be) then it is
difficult to get back to blank.

This demo shows one of several ways to accomplish this task.
This version is a bit more robust in that it also handles
the situation where the user supplies their own value - you
see unless disabled by an API call the combobox will accept
user input much the same way a textbox will as I discuss in
the message snippet below:

The one thing that can be a "gotcha"  when using the
combobox is that the USER can type a value into the
combobox.  If you do not do something to handle that
condition then your program will appear to leave the user in
the lurch if they were to assume their value was good but
you appeared to ignore it.  This happens when you simply
retrieved the index or item from the combobox and presume
the user had typed nothing into the control and then
displayed your indexed item and not the user's input.

That is why I recommended testing the combobox with the
command CONTENTS? so that you can determine whether the use
actually entered an alternate value.  This demo will check
for user input and then ADD it to the value list if it 
is unique:

'Code for LB3
'test combo reset to null - Brad Moore

    Dim item$(15)

    item$(1) = "Black"
    item$(2) = "Buttonface"
    item$(3) = "White"

    ttlItems = 3

    ForegroundColor$ = "Black"
    BackgroundColor$ = "Buttonface"
    TexteditorColor$ = "White"
    TextboxColor$    = "White"
    ComboboxColor$   = "White"
    ListboxColor$    = "White"

[WindowSetup]
    NoMainWin
    WindowWidth = 193 : WindowHeight = 219
    UpperLeftX = Int((DisplayWidth-WindowWidth)/2)
    UpperLeftY = Int((DisplayHeight-WindowHeight)/2)

[ControlSetup]

Button      #main.reset, "Force Reset",[reset],UL, 35, 60,
105, 25
Button      #main.quit, "Quit",[quit],UL, 35, 140, 105, 25
Button      #main.info, "Get Info",[info],UL, 35, 100, 105,
25
Combobox    #main.combo1,item$(,[combo1.click], 20, 20, 142,
300

Open "Test Combo" For Dialog As #main

    Print #main, "trapclose [quit]"
    Print #main, "font ms_sans_serif 10"

[loop]
    Wait

[quit]

    Close #main
    End

[reset]
    Print #main.combo1, "! "

    GoTo [loop]


[info]
    print #main.combo1, "contents? text$"
    Print #main.combo1, "selection? selected$"
    Print #main.combo1, "selectionindex? index"
    if text$ <> selected$ then
       if text$ > " " then
          'the user has entered an all new value
          '(maybe we will add it to the list)
          gosub [addToItems]
       else
           index = 0
           selected$ = ""
       end if
    end if
    'report what we got...
    Notice "Combobox Info" + Chr$(13) + "Index selected: " +
Str$(index) + _
           "   Value Selected: " + selected$
    GoTo [loop]



[combo1.click]
    Print #main.combo1, "selection? selected$"
    GoTo [loop]

[addToItems]
    if ttlItems = 15 then
        Notice "Error" + Chr$(13) + _
               "Sorry can not add more items to list box"
        return
    end if

    'keep track of total items
    ttlItems = ttlItems + 1

    item$(ttlItems) = text$
    print #main.combo1, "reload"
    print #main.combo1, "selectindex "; ttlItems

    'Now get the values again
    Print #main.combo1, "selection? selected$"
    Print #main.combo1, "selectionindex? index"


---------------------------------------------------------
---------------------------------------------------------
Information: About the archive

Attached to the newsletter is an archive (called
nl101Archive.zip) which contains several items that go with
this newsletter.  The following is the contents of the
archive:

APIradiobuttons.bas  - Demo code for API created
                       radiobuttons
Comboboxdemo.bas     - Demo code to show combobox in action
numbword.bas         - Demo code to show number to text 
                       conversion
paths.bas            - Demo of path and filename parser from 
                       Tips section
WMLiberty102.zip     - latest WMLiberty dll referred to in 
                       API article
Resources.rtf        - Formatted version of Resources article
Beginners Guide to API.rtf - formatted version of API
                             article


---------------------------------------------------------
---------------------------------------------------------
SUBMISSIONS

The Liberty BASIC Newsletter encourages all LB programmers
to submit articles for publication.  Everyone has something
valuable to say, from beginners to veteran LBers.  Consider
sharing a code routine, with explanation.  Perhaps you can
review a favorite LB website, or program, or coding tool?
Why not submit a list of questions that have been nagging
at you?  How about sharing your favorite algorithm?

---------------------------------------------------------
---------------------------------------------------------
    Comments, requests, submissions or corrections:
Simply reply to this message, or contact a member of the
team!

               The Team:
     Alyce Watson: alycewatson@charter.net
     Brad Moore: brad.moore@weyerhaeuser.com
     Tom Nally:  SteelWeaver52@aol.com
     Carl Gundel: carlg@libertybasic.com
     Bill Jennings: bbjen@bigfoot.com
---------------------------------------------------------
---------------------------------------------------------

