---------------------------------------------------------
The Liberty Basic Newsletter - Issue #71 - APR 2000
       2000, Cliff Bros and Alyce Watson
             All Rights Reserved
---------------------------------------------------------
In this issue:
	Using the runtime engine 
	Changing the runtime icon in the LB editor
	Changing the runtime icon ourselves
	File manipulation via api
	Doing the manipulations with LB functions
	Extracting and viewing icon files
	Making an icon
	A simple icon viewer/editor
	Icon file format
	
In future issues:
    Writing output 'code'
    Launching the default web browser and email client
    Fun with the caret
    Timing and benchmarking
    Making professional-looking applications
    Do it with math?
---------------------------------------------------------
                      NOTE

We try to present a variety of articles to satisfy as
many different areas of interest, and as many levels of
programming skill as possible.  If a particular newsletter
does not appeal to you, please be patient.  Ideas for
newsletter topics are always welcome, as are submissions
of articles.  Thanks.
---------------------------------------------------------
USING THE RUNTIME ENGINE

Liberty BASIC allows you to distribute your programs to the
public.  When you register, you get a password that gives
you the ability to use the runtime engine to run your
tokenized code.

The runtime engine is named "run.exe".  You may make 
standalone programs by tokenizing your code with password.
In version 1.42 of Liberty BASIC, you need only enter your
username and password once in the Liberty BASIC editor, and
all tokenized code created after that will automatically
contain your password.  Look in the Setup menu for "Enter
registration code."

To make a TKN, load the desired BASIC code into the LB editor,
and choose MAKE TKN from the RUN menu.

Once you have made a tkn, you must make a copy of the runtime 
engine and rename it to match the name of your tokenized 
file.  If your tokenized file is called "cruncher.tkn", then 
rename "run.exe" to "cruncher.exe".

In addition to the TKN, the runtime engine, and any bitmaps,
text files, or other files required by your program, you
must include a set of runtime DLLs in your distribution
package, so that people who do not have the Liberty BASIC
language installed on their systems can run your program.
These DLLs must either be in the program directory, the
Windows directory, the Windows/system directory, or in 
the user's path statement.

  VWVM11.DLL
  VWBAS11.DLL
  VWSIGNON.DLL
  VWFONT.DLL
  VWFLOAT.DLL
  VWABORT.DLL
  VWDLGS.DLL

You must also include VWSIGNON.BMP.  Here are the instructions
for using and altering this bitmap, directly from the
Liberty BASIC Helpfile:

c) You will want to edit the startup bitmap VWSIGNON.BMP 
to your liking using Paintbrush.  The bitmap should not 
be more than 16 colors, and it shouldn't be much larger than 
the supplied example.  These color and size restrictions are 
to minimize the possibility of protection faults happening 
during program startup.

Because of licensing issues for some development resources we 
used to create Liberty BASIC, your vwsignon.bmp file must make 
mention of:

  Portions copyright 1991 Digitalk, Inc.

Take a look at the included VWSIGNON.BMP.  The Digitalk, Inc 
copyright notice is very small.  Feel free to do the same 
with the above required notices.


---------------------------------------------------------
CHANGING THE RUNTIME ICON

It is possible to change the icon that displays with your 
program from the Liberty BASIC torch default icon, to any 
16 color icon of your choice.  Remember that the format 
MUST be 16 colors.

To do this from within the Liberty BASIC editor, you must
have your system set to 16 color display mode.  You can do
this in your Control Panel settings, or by booting in
Safe Mode.  This is a small bug in Liberty BASIC.  

After you have placed your display in 16 color resolution,
go to the Setup menu of the Liberty BASIC editor and choose, 
"Change runtime icon."  Just follow the directions.  When you 
are done, you may set your display resolution back to normal.

---------------------------------------------------------
CHANGING THE RUNTIME ICON OURSELVES

The runtime engine, run.exe contains the data for the runtime
icon.  Changing the icon simply requires that we remove the
data for the torch icon from the file and replace it with
the data for the desired 16 color icon.

Anthony Liquori has provided the code to accomplish this
substitution.  Using this method, we may change the runtime 
icon without changing the display color resolution of
our systems.  Brian Pugh has added a very nice gui.  We'll
use their code in our open source editor to provide a
runtime icon changer.
---------------------------------------------------------
FILE MANIPULATION VIA API

Anthony has chosen to open, read and write to the runtime
engine by using API calls.  For an excellent explanation
of file manipulation, Dean Hodgson's tutorial is a MUST HAVE.  
Get it here:  http://alyce.50megs.com/sss/

What follows is a brief summary of the method used to
change the runtime icon.  It is not a complete explanation.
The entire program is included in this newsletter, and it
has been integrated into the open source editor, whose
code is attached.  This method requires intermediate to
advanced understanding of API's and file manipulation
in Liberty BASIC.  It is great to know that we don't need
to understand it to be able to use this handy tool.


First, the icon file is opened, and the data is read into
a string variable called icont$:

    open icon$ for input as #1icon    'open up the icon
    icont$=input$(#1icon,lof(#1icon)) 'read the icon
    close #1icon                      'close icon


Anthony has determined the part of the icon data that
will be needed.  The header of the icon file will not be
placed into the runtime engine, so the first 21 bytes
will not be used.  The part of the icon file that will be
copied into the runtime engine starts at byte 22.

    ico=hexdec("16") '= 22 in decimal numbers 

'skip the header and put all the actual data into icondata$
    icondata$=mid$(icont$,ico,len(icont$))

'Editor's note:  the above appears to be incorrect, and
'should be:  icondata$=mid$(icont$,ico) or
'            icondata$=mid$(icont$,ico,len(icont$)-ico)


Next, the runtime engine file is opened with the API 
function, _lopen:

    ' Opens up runtime for write & read access and returns the handle into hFile
    calldll #kernel,"_lopen",runtime$ as ptr,_
        _OF_WRITE as short,hFile as word

Be sure to check Dean's explanations or these functions!  The
function _llseek is used to position the pointer within the
file.  It is first positioned at the beginning of the file.

    ' Moves the file pointer to the beginning of the file,
    ' this is why i used apis instead of lb
    calldll #kernel,"_llseek",hFile as word,_
        0 as long,0 as short,result as long

Next, the file pointer is moved to the spot where the new data 
will be inserted.  This is at position 6655, which is equivalent
to hexdec("19ff")

    runpos=hexdec("19ff")  
    ' Moves to the position of the icon resource
    calldll #kernel,"_llseek",hFile as word,_
        runpos as long,1 as short,result as long

With the pointer at the proper position, the icon data that
was extracted from the icon file is written into place with
the function _lwrite:

    calldll #kernel,"_lwrite",hFile as word,icondata$ as ptr,_
        iconlength as short,result as short

A file opened via API must be closed via API, with _lclose:

    calldll #kernel,"_lclose",hFile as word,result as short

---------------------------------------------------------
DOING THE MANIPULATIONS WITH LB FUNCTIONS

Here is a small program that also changes the icon in the
runtime engine, but this one does it with straight Liberty
BASIC functions -- no API calls.  The comments serve as 
the documentation.

    filedialog "Choose icon",DefaultDir$+"\*.ico",icon$


'Open the chosen icon file and read the
'data into a string called t$:

    open icon$ for input as #1
    t$=input$(#1,lof(#1))
    close #1


'For demo purposes, unrem these lines to read file header:
'    for i = 1 to 21
'        print asc(mid$(t$,i,1))
'    next i


'The first bytes are the header, so
'skip header and take data starting at 21:

    start=21


'Skip the header and put all the actual data into icondata$

    icondata$=mid$(t$,start)



'Check to see if the icon is 32 x 32 by
'checking to see if byte 7 and byte 8 are chr$(32):

    if mid$(t$,7,1)<>chr$(32) or mid$(t$,8,1)<>chr$(32) then [wrong.size]


'Check to see if the icon is 16 color
'by checking byte 9 to see if it is chr$(16):

    if mid$(t$,9,1)<>chr$(16) then [wrong.color]


    filedialog "Choose runtime engine",DefaultDir$+"\*.exe",runtime$ 


'Open runtime engine file and read it into
'a string called r$:

    open runtime$ for input as #2
    r$=input$(#2,lof(#2))
    close #2


    cursor hourglass
    print "Please wait..."


'The position for icon data in runtime engine:

    runpos=6655


'The length of the actual icon data:

    length=len(icondata$)


'The position after icon data in runtime:

    newpos=runpos+length


'Concatenate data strings.  The
'beginning of runtime file comes first,
'then replace icon data with icondata$,
'then append the end of the runtime file:

    newrun$=left$(r$,runpos-1)+icondata$+mid$(r$,newpos)


'Open a file called test.exe to make a test of the
'runtime engine with the new icon.
'Write the string of data to the file:

    open DefaultDir$+"\test.exe" for output as #test
    print #test, newrun$
    close #test

    cursor normal
print DefaultDir$+"\Test.exe contains new icon."

input a$

[wrong.size]
print "Error.  Icon is not 32x32."
end

[wrong.color]
print "Error.  Icon is not 16 colors."
end
---------------------------------------------------------
EXTRACTING AND VIEWING ICON FILES

It isn't difficult to extract and view icon files.  Note
that these files can be extracted for viewing from ICO,
EXE and DLL files, but the runtime icon changer requires
that the file be in ICO format.

The steps for icon extraction and viewing:

1)  GetDC of your program's window with USER.

    calldll #iconuser,"GetDC",_
	hico as word,_	'window handle
	hicodc as word	'returns handle of device context

2)  Obtain the instance handle, with GetWindowWord from USER:

    calldll #iconuser,"GetWindowWord",_
	hico as word,_			'window handle
	_GWL_HINSTANCE as word,-	'flag requesting instance handle
	hCurrentInst as word		'returns instance handle

3)  The icon's handle is obtained with a call to SHELL to
    ExtractIcon:

    calldll #iconshell,"ExtractIcon",_
	hCurrentInst as word,_	'instance handle
	szFile$ as ptr,_		'name of file containing icon
	0 as ushort,_		'icon index, 0=first icon in file
	hicon as word		'returns handle of icon

4)  Once the handle of the icon is obtained, it can be used
    in a call to USER to DrawIcon, which displays the icon
    on the window whose DC is used in the call, at the location
    specified.  Note that this icon display is not flushed, which
    means that the icon will not 'stick' if the window is covered
    and then refreshed.

    calldll #iconuser,"DrawIcon",_
	hicodc as short,_		'device context handle of window
	x as short,_		'x location to display icon
	y as short,_		'y location to display icon
	hicon as word,_		'handle of icon to display
	Ret as short

5)  Any time you get a Device Context (DC) you must release it before
    the program ends:

    calldll #iconuser,"ReleaseDC",_
	hico as word,_	'window handle
	hicodc as word,_	'handle of device context
	Ret as ushort

---------------------------------------------------------
' Icon changer code begins here
' This cannot make Icons
' Ok first I have tried to document this well
' If you don't understand or something doesn't work, PLEASE
' email me at ajl13@bellatlantic.net
' Oh, real quick. I, Anthony Liguori, copyright this or
' whatever under the GNU copyright
' So you can play with or include this in your programs as
' long as you give me credit
' Heh-hee. It didn't take that long, but...

' Modified Feb, 1999, by Brian D. Pugh
' Cosmetic changes to GUI
' Retains path after selecting runtime exe, in anticipation
' that the icon required is in the same dir as the runtime
' Shows current icon in selected runtime exe
' Shows new icon in runtime exe AFTER pressing the Change! button
' Won't let you select an icon until you have selected the runtime exe
' Icon change coding remains the same (couldn't alter anything of Anthony's!)

    UpperLeftX=int((DisplayWidth-268)/2)
    UpperLeftY=int((DisplayHeight-230)/2)
    WindowWidth=268:WindowHeight=230

    textbox #icon.Textbox2,21,30,174,24
    textbox #icon.Textbox1,21,83,174,24
    button #icon.Button4,"...",[get.runtime],UL,216,30,30,24
    button #icon.Button3,"...",[get.icon],UL,216,83,30,24
    button #icon.Button5,"Change!",[change.it],UL,21,124,69,24
    button #icon.Button6,"Exit",[exit.now],UL,176,124,69,24

    open "Icon changer V0.90b" for graphics_nsb_nf as #icon

    print #icon,"trapclose [exiticon]"
    print #icon,"fill darkcyan;place 21 22"
    print #icon, "color white;backcolor darkcyan;\Runtime Engine Path"
    print #icon,"place 21 74;\Icon Path"
    print #icon,"flush"

    open "user" for dll as #iconuser
    open "shell" for dll as #iconshell

[mainloop]
    input loop$

[exiticon]
    close #iconuser:close #iconshell:close #icon
    goto [loop]

[get.runtime]
    filedialog "Find Runtime Engine","*.exe",runtime$
    print #icon.Textbox2,lower$(runtime$)
    gosub [ShowBefore]
    goto [mainloop]

[get.icon]
    if runtime$="" then notice "Icon Changer error"+chr$(13)+_
    "Please select the Runtime Engine Path first":goto [mainloop]

    icopath$=runtime$
    while instr(icopath$,"\"):icopath$=mid$(icopath$,instr(icopath$,"\")+1):wend
    icopath$=left$(runtime$,len(runtime$)-len(icopath$))
    icopath$=lower$(icopath$)+"*.ico"
    filedialog "Icon",icopath$,icon$
    print #icon.Textbox1,lower$(icon$)
    goto [mainloop]

[change.it]
    print #icon.Textbox2,"!contents?"
    input #icon.Textbox2,runtime$
    print #icon.Textbox1,"!contents?"
    input #icon.Textbox1,icon$ 
    gosub [CheckRuntimeEngine]
    if error=0 then
        gosub [CheckIcon]
        if error=0 then
            gosub [change]
            gosub [ShowAfter]
        end if
    end if
    if error=1 then notice "Error changing Runtime Icon"
goto [mainloop]

[exit.now]
goto [exiticon]

[change]
    success=0
    ico=hexdec("16") 'I used a hex editor for the offsets, it's easier for me
    runpos=hexdec("19ff")  ''        ''
    open icon$ for input as #1icon 'open up the icon
    icont$=input$(#1icon,lof(#1icon)) 'read the icon

'skip the header and put all the actual data into icondata$
'    icondata$=mid$(icont$,ico,len(icont$))    'ERROR?
    icondata$=mid$(icont$,ico,len(icont$)-ico) 'substitute this

    close #1icon 'close icon
    iconlength=len(icondata$) 'improves speed
    open "kernel" for dll as #kernel 'loads kernel

    ' Opens up runtime for write & read access and returns the handle into hFile
    calldll #kernel,"_lopen",runtime$ as ptr,_
        _OF_WRITE as short,hFile as word

    ' Moves the file pointer to the beginning of the file,
    ' this is why i used apis instead of lb
    calldll #kernel,"_llseek",hFile as word,_
        0 as long,0 as short,result as long

    ' Moves to the position of the icon resource
    calldll #kernel,"_llseek",hFile as word,_
        runpos as long,1 as short,result as long

    calldll #kernel,"_lwrite",hFile as word,icondata$ as ptr,_
        iconlength as short,result as short

    calldll #kernel,"_lclose",hFile as word,result as short
    close #kernel
    return

[CheckIcon]
    error=0
    if icon$<>"" then
    open icon$ for input as #1icon
    icont$=input$(#1icon,lof(#1icon))
    close #1icon
    else error=1
    end if
    ' check to see if the icon is 32 x 32
    if mid$(icont$,7,1)<>" " or mid$(icont$,8,1)<>" " then error=1
    ' check to see if the icon is 16 colour
    if mid$(icont$,9,1)<>chr$(16) then error=1
    ' ok, that's enough error checking for me :)
    return

[CheckRuntimeEngine]
    error=0
    if runtime$="" then error=1
    return

[ShowBefore]
    print #icon,"discard;redraw"
    szFile$=runtime$+chr$(0):hico=hWnd(#icon):x=120:y=160
    calldll #iconuser,"GetDC",hico as word,hicodc as word
    calldll #iconuser,"GetWindowWord",hico as word,_
        _GWL_HINSTANCE as word,hCurrentInst as word

    calldll #iconshell,"ExtractIcon",hCurrentInst as word,_
        szFile$ as ptr,0 as ushort,hicon as word

    if hicon>1 then
        print #icon,"place 21 174;\Existing"
        print #icon,"place 21 190;\Icon >>>         "
        calldll #iconuser,"DrawIcon",hicodc as short,_
            x as short,y as short,hicon as word,Ret as short
    else
        print #icon,"place 21 190;\Icon - None"
    end if

    print #icon,"flush"
    calldll #iconuser,"ReleaseDC",hico as word,hicodc as word,Ret as ushort
    return

[ShowAfter]
    print #icon,"discard;redraw"
    szFile$=runtime$+chr$(0):hico=hWnd(#icon):x=120:y=160
    calldll #iconuser,"GetDC",hico as word,hicodc as word

    calldll #iconuser,"GetWindowWord",hico as word,_
        _GWL_HINSTANCE as word,hCurrentInst as word

    calldll #iconshell,"ExtractIcon",hCurrentInst as word,_
        szFile$ as ptr,0 as ushort,hicon as word

    if hicon>1 then
        print #icon,"place 21 174;\New       "
        print #icon,"place 21 190;\Icon >>>  "
        calldll #iconuser,"DrawIcon",hicodc as short,_
            x as short,y as short,hicon as word,Ret as short
    end if

    print #icon,"flush"
    calldll #iconuser,"ReleaseDC",hico as word,_
        hicodc as word,Ret as ushort
    return


---------------------------------------------------------
MAKING AN ICON

An icon editor is attached to this newsletter.  It was
written in Liberty BASIC.  It will allow you to extract
icon files from ICO, EXE and DLL files, or to begin a
new icon yourself.  You may draw with all 16 colors to
make an icon you like, then save it as an ICO file, which
you can then use with your runtime engine.  It is a simple
editor, and does not provide for a transparent color option.

There are many freeware and shareware icon editors available
on the internet.

---------------------------------------------------------
A SIMPLE ICON VIEWER/EDITOR

The following program is presented as is, with little 
explanation. It uses Liberty BASIC string and file 
functions to obtain the data for the icon drawn by the 
user, and writes an icon file.

The format for an icon file requires information about the icon,
followed by a palette of rgb color values.  The data for each
pixel of the icon points at one of the 16 palette entries.  An
icon file also contains mask information, so that desired parts
of the icon will be drawn transparent.  This author has yet to
figure out the proper way to write mask information into the
file, so anyone who can add the the knowledge base is
encouraged to step forward!  The file format reference information
for icons follows the program code, for the intrepid.


'  This program will open icon files, or DLL's or EXE's and
'  display icons for editing.  You may alter these, or draw
'  icons of your own by choosing a color and drawing with
'  the mouse cursor.  There is no transparent color function
'  in this version of the Icon Machine.  Icons will be saved
'  in 16-color format, suitable for use with the Liberty
'  BASIC runtime engine.
'
'  16-Color Icon Machine (c) Alyce Watson 1999, 2000
'  contact awatson@wctc.net

    PixColor=256*256*256 + 256*256 + 256 'white
    cl=256*256*10 + 256*10 + 10 'almost black for grid lines

    DIM k(15)         'make a palette
    k(15)=0           'black
    k(14)=8421504     'darkgray
    k(13)=12632256    'lightgray
    k(12)=16777215    'white
    k(11)=8388608     'darkblue
    k(10)=16711680    'blue
    k(9)=32768        'darkgreen
    k(8)=65280        'green
    k(7)=8421376      'darkcyan
    k(6)=16776960     'cyan
    k(5)=32896        'brown
    k(4)=65535        'yellow
    k(3)=128          'darkred
    k(2)=255          'red
    k(1)=8388736      'darkpink
    k(0)=16711935     'pink

    DIM k$(15)        'set values for palette entries in hex
    for i = 0 to 9
        k$(i)=str$(i)
    next i
    k$(10)="A"
    k$(11)="B"
    k$(12)="C"
    k$(13)="D"
    k$(14)="E"
    k$(15)="F"

'write the ico file header for 16-color icon, using palette above
    head$="0 0 1 0 1 0 32 32 16 0 0 0 0 0 232 2 0 0 22 0 0 0 40 0 0 0 32 0 0 0 64 0 0 0 1 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 255 0 128 0 128 0 0 0 255 0 0 0 128 0 0 255 255 0 0 128 128 0 255 255 0 0 128 128 0 0 0 255 0 0 0 128 0 0 255 0 0 0 128 0 0 0 255 255 255 0 192 192 192 0 128 128 128 0 0 0 0 0 0 0 "
    DIM header(127)
    for i=1 to 127
        header(i)=val(word$(head$,i))
    next i
    head$="" 'free memory


    WindowWidth = 500
    WindowHeight = 400
    UpperLeftX=1:UpperLeftY=1
    nomainwin

    menu #main, "&File","&New",[new],"&Open Icon",[open],_
    "&Update Icon View",[update],"&Save Icon",[save],"E&xit",[exit]
    menu #main, "&Help","H&elp",[help],"&About",[about]
    open "16-Color Icon Machine" for graphics_nsb_nf as #main
    print #main, "trapclose [exit]"
    Handle=hwnd(#main)

    open "user" for dll as #user
    open "gdi" for dll as #gdi

    Calldll #user, "GetDC", Handle as word, hdc as word
    calldll #user, "GetWindowWord",_
    Handle as word,_
    _GWL_HINSTANCE as word,_
    hCurrentInst as word


    print #main, "down"
    print #main, "color 1 1 1;backcolor white;place 400 0;boxfilled 500 20"
    print #main, "backcolor lightgray;place 400 20;boxfilled 500 40"
    print #main, "backcolor darkgray;place 400 40;boxfilled 500 60"
    print #main, "backcolor black;place 400 60;boxfilled 500 80"
    print #main, "backcolor yellow;place 400 80;boxfilled 500 100"
    print #main, "backcolor brown;place 400 100;boxfilled 500 120"
    print #main, "backcolor green;place 400 120;boxfilled 500 140"
    print #main, "backcolor darkgreen;place 400 140;boxfilled 500 160"
    print #main, "backcolor red;place 400 160;boxfilled 500 180"
    print #main, "backcolor darkred;place 400 180;boxfilled 500 200"
    print #main, "backcolor blue;place 400 200;boxfilled 500 220"
    print #main, "backcolor darkblue;place 400 220;boxfilled 500 240"
    print #main, "backcolor cyan;place 400 240;boxfilled 500 260"
    print #main, "backcolor darkcyan;place 400 260;boxfilled 500 280"
    print #main, "backcolor pink;place 400 280;boxfilled 500 300"
    print #main, "backcolor darkpink;place 400 300;boxfilled 500 320;flush"
    gosub [grid]
    FileName$="UNTITLED.ICO"
    gosub [print.name]


[loop]
    print #main, "setfocus; when leftButtonDown [mouse.down]"
    print #main, "when leftButtonMove [mouse.down]"
    print #main, "place 5 80;boxfilled 45 120"
    Input a$ 


[mouse.down]
    if MouseX<60  OR MouseY<0 OR MouseY>320 then [loop]
    if MouseX>60 and MouseX<380 then [put.color]
    if MouseX>400 then [get.color]
    goto [loop]


[get.color]
    Y=MouseY
    if Y<20 then print #main, "backcolor white":goto [loop]
    if Y<40 then print #main, "backcolor lightgray":goto [loop]
    if Y<60 then print #main, "backcolor darkgray":goto [loop]
    if Y<80 then print #main, "backcolor black":goto [loop]
    if Y<100 then print #main, "backcolor yellow":goto [loop]
    if Y<120 then print #main, "backcolor brown":goto [loop]
    if Y<140 then print #main, "backcolor green":goto [loop]
    if Y<160 then print #main, "backcolor darkgreen":goto [loop]
    if Y<180 then print #main, "backcolor red":goto [loop]
    if Y<200 then print #main, "backcolor darkred":goto [loop]
    if Y<220 then print #main, "backcolor blue":goto [loop]
    if Y<240 then print #main, "backcolor darkblue":goto [loop]
    if Y<260 then print #main, "backcolor cyan":goto [loop]
    if Y<280 then print #main, "backcolor darkcyan":goto [loop]
    if Y<300 then print #main, "backcolor pink":goto [loop]
    if Y<320 then print #main, "backcolor darkpink":goto [loop]
    goto [loop]


[put.color]  'color working area and preview area
    if MouseX/10 = int(MouseX/10) then [loop] 'mouse is on grid line
    if MouseY/10 = int(MouseY/10) then [loop] 'mouse is on grid line
    filx=MouseX:fily=MouseY
     calldll #gdi, "FloodFill", _
        hdc as word, _
        filx as short, _
        fily as short, _
        cl as long, _  'boundary color for flood fill
      results as short

    iconX=int(((filx-60)/10)+5)
    iconY=int((fily/10)+200)

    calldll #gdi, "GetPixel",_
        hdc AS short,_
        filx AS short,_
        fily AS short,_
        pixColor AS long


    calldll#gdi,"SetPixel",_
        hdc as word,_
        iconX as short,_
        iconY as short,_
        pixColor as long,_
        result as long

    goto [loop]

[open]
    gosub [clear]
    filedialog "Choose Icon","*.ico;*.exe;*.dll",FileName$
    if FileName$="" then [loop]
    File$=FileName$+chr$(0)

    open "shell" for dll as #shell
    calldll #shell, "ExtractIcon",_
        hCurrentInst as word,_
        File$ as ptr,_
        0 as ushort,_
        hicon as word  'returns icon handle
        close #shell

    if hicon>1 then
        calldll #user, "DrawIcon",_ 'draw icon from file
        hdc as short,_
        0 as short,_
        0 as short,_
        hicon as word,_
        Ret as short

        calldll #user, "DrawIcon",_ 'draw icon to edit
        hdc as short,_
        5 as short,_
        200 as short,_
        hicon as word,_
        Ret as short
    End if


    calldll #gdi,"StretchBlt",_  'draw large copy of icon
        hdc as word,_
        60 as word,_
        0 as word,_
        320 as word, _
        320 as word,_
        hdc as word,_
        0 as word,_
        0 as word,_
        32 as word,_
        32 as word,_
        _SRCCOPY as long,_
        r as ushort

    gosub [grid]    'draw grid over large copy
    gosub [print.name]
    goto [loop]


[save]
    filedialog "Save as...","*.ico",savefile$
    if savefile$="" then [loop]

    cursor hourglass
    bits$="" 'reset string to hold bit information

    x2=5:y2=232  'get fresh copy for saving
    for y1=315 to 5 step -10
        for x1=65 to 375 step 10
            gosub [get.pixel]
            gosub [draw.new.icon]
            gosub [add.to.file]
        next x1
    next y1
    gosub [write.file]
    cursor normal
    goto [loop]

[write.file]
    saveicon$="" 'reset
    for i = 1 to 126
        saveicon$=saveicon$+chr$(header(i))
    next i

    for i = 1 to 1026 step 2
        saveicon$=saveicon$+chr$(hexdec(mid$(bits$,i,1)+mid$(bits$,i+1,1)))
    next i

    for i = 1 to 127
        saveicon$=saveicon$+chr$(0)
    next i

    open savefile$ for output as #sf
        print #sf, left$(saveicon$,766)
    close #sf
    cursor normal
    notice "File saved as "+lower$(savefile$)
    goto [loop]


[update]
    cursor hourglass
    x2=5:y2=200
    for y1=315 to 5 step -10
        for x1=65 to 375 step 10
            gosub [get.pixel]
            gosub [draw.new.icon]
        next x1
    next y1
    cursor normal
    goto [loop]


[draw.new.icon]
    calldll#gdi,"SetPixel",_
        hdc as word,_
        x2 as short,_
        y2 as short,_
        pixColor as long,_
        result as long
    x2=x2+1
    if x2>=37 then x2=5:y2=y2-1
    RETURN

[add.to.file]  'check color and add bit to bit string
    for j=0 to 15
        if pixColor=k(j) then bits$=bits$+k$(j)
    next j
    return

[get.pixel]
    calldll #gdi, "GetPixel",_
        hdc AS short,_
        x1 AS short,_
        y1 AS short,_
        pixColor AS long
    RETURN


[grid] 'color 10 10 10 is almost black
    print #main, "down;color 10 10 10;size 1"
    for x=60 to 380 step 10
        print #main, "line ";x;" 0 ";x;" 320"
    next x

    for y=0 to 320 step 10
        print #main, "line 60 ";y;" 380 ";y
    next y
    print #main, "color 10 10 10;place 4 199;box 38 233"
    print #main, "backcolor white;place 5 254;|view"
    print #main, "place 5 140;|color"
    RETURN


[print.name]
    print #main, "backcolor white"
    print #main, "place 100 340;|";FileName$+space$(100)
    RETURN


[clear]
    print #main, "place 0 0;color white;backcolor white;boxfilled 381 321"
    RETURN


[new]
    FileName$="UNTITLED.ICO"
    gosub [clear]
    gosub [grid]
    gosub [print.name]
    goto [loop]


[exit]
    calldll #user, "ReleaseDC", Handle as word, hdc as word, Ret as ushort
    close #main
    close #user
    Close #gdi
    end

[help]
    notice "Help"+chr$(13)+"Either choose file/open to open an existing icon, or file/new to begin a new icon.  Click on the drawing color desired.  Click and drag the mouse in the grid to color the icon.  To save the result as a 16-color icon, choose file/save.  Only 16 color icons may be saved, and there is no transparent color function in this version."
    goto [loop]

[about]
    notice "16-Color Icon Machine "+chr$(169)+" Alyce Watson, 1999-2000."
    goto [loop]

---------------------------------------------------------
ICON FILE FORMAT (from reference materials)

typedef struct tagBITMAPINFOHEADER {    /* bmih */
    DWORD   biSize;
    LONG    biWidth;
    LONG    biHeight;
    WORD    biPlanes;
    WORD    biBitCount;
    DWORD   biCompression;
    DWORD   biSizeImage;
    LONG    biXPelsPerMeter;
    LONG    biYPelsPerMeter;
    DWORD   biClrUsed;
    DWORD   biClrImportant;
} BITMAPINFOHEADER;

Icon Image

Each icon-resource file contains one icon image for each image identified in
the icon directory. An icon image consists of an icon-image header, a color
table, an XOR mask, and an AND mask. The icon image has the following form:


BITMAPINFOHEADER    icHeader;
RGBQUAD             icColors[];
BYTE                icXOR[];
BYTE                icAND[];

The icon-image header, defined as a BITMAPINFOHEADER structure, specifies the
dimensions and color format of the icon bitmap. Only the biSize through
biBitCount members and the biSizeImage member are used. All other members
(such as biCompression and biClrImportant) must be set to zero.

The color table, defined as an array of RGBQUAD structures, specifies the
colors used in the XOR mask. As with the color table in a bitmap file, the
biBitCount member in the icon-image header determines the number of elements
in the array. 

The XOR mask, immediately following the color table, is an array of BYTE
values representing consecutive rows of a bitmap. The bitmap defines the
basic shape and color of the icon image. As with the bitmap bits in a bitmap
file, the bitmap data in an icon-resource file is organized in scan lines,
with each byte representing one or more pixels, as defined by the color
format. 

The AND mask, immediately following the XOR mask, is an array of BYTE values,
representing a monochrome bitmap with the same width and height as the XOR
mask. The array is organized in scan lines, with each byte representing 8
pixels.

When Windows draws an icon, it uses the AND and XOR masks to combine the icon
image with the pixels already on the display surface. Windows first applies
the AND mask by using a bitwise AND operation; this preserves or removes
existing pixel color.  Windows then applies the XOR mask by using a bitwise
XOR operation. This sets the final color for each pixel.
---------------------------------------------------------
Brosco and Alyce have written a Book for Liberty BASIC,
which is available in electronic form on a CDROM.
For details:  http://alyce.50megs.com/sss/cd.htm
---------------------------------------------------------
Newsletter compiled and edited by: Brosco and Alyce.
Comments, requests or corrections: Hit 'REPLY' now!
mailto:brosco@orac.net.au or mailto:awatson@wctc.net
---------------------------------------------------------