Liberty Basic is develeopped by Carl Gundel
Original Newsletter compiled by Alyce Watson and Brosco
Translation to HTML: Raymond Roumeas

The Liberty Basic Newsletter - Issue #71 - APR 2000

© 2000, Cliff Bros and Alyce Watson All Rights Reserved

In this issue:

  1. Using the runtime engine
  2. Changing the runtime icon in the LB editor
  3. Changing the runtime icon ourselves
  4. File manipulation via api
  5. Doing the manipulations with LB functions
  6. Extracting and viewing icon files
  7. Making an icon
  8. A simple icon viewer/editor
  9. Icon file format

In future issues:


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.


1. 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.


2. 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.


3. 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.


4. 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


5. 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

6. 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@b...
' 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

7. 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.


8. 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@w...
 
    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]

9. 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@o... or mailto:awatson@w...