Maintaining checkbox states
Tidbits from the community
Liberty Basic 4
New Alternate Forum
Using the Tsunami Database
Wizard Framework
Links to LB Sites
Update on 10th Anniversary Contest
Extracting Icons And Saving Them As Bitmaps
Applying Symbolic Logic
QuadClicks
Simple Math For Moving Objects
Event Driven Programming - Part 2
The Beginners Series - Part 1
This tutorial expects the reader to have a fair understanding of the Windows API and Liberty BASIC graphics functions. [ed: the demo file is part of saveicon.zip]
We can load icons into memory with an API call, LoadImageA. This allows us to access single icon files with the extension *.ico. If we want to access icons from other types of files, such as executables and libraries, we can use ExtractIconA. To use the function, we need to have an instance handle to our program's window, which we obtain with the function GetWindowLongA, and a type flag of _GWL_HINSTANCE. The function returns the instance handle. Here is the function, wrapped in a Liberty BASIC function:
Function GetWindowLong(hWindow, type) CallDLL #user32, "GetWindowLongA",_ hWindow As Long, type As Long,_ GetWindowLong As Long End Function
The function to extract the icon requires the instance handle, the filename of the file containing the icon on disk, and a flag indicating the zero-based index of the desired icon. If this flag is -1, the function returns the number of icons in the file. An icon library file (*.icl) or a dynamic link library (*.dll) may contain dozens of icons.
hInst=GetWindowLong(hWindow, _GWL_HINSTANCE) CallDLL #shell32, "ExtractIconA",_ hInst As Long,_ 'instance handle of window file$ As Ptr,_ 'disk file name index As Long,_ 'index of desired icon result As Long 'returns icon handle or number of icons
To simplify our demo, we are passing an index of 0 to extract the first icon in the disk file. We could instead, use an index of -1 to obtain the number of icons in the file, then allow the user to choose the desired icon in a preview window. Perhaps some intrepid soul will modify the demo to do just that, and share it with the group?
Here is the ExtractIconA function wrapped in a Liberty BASIC function with an icon index of 0, so it will return the handle of the first icon in the file:
Function ExtractIcon(hWindow, file$) hInst=GetWindowLong(hWindow, _GWL_HINSTANCE) CallDLL #shell32, "ExtractIconA",hInst As Long,_ file$ As Ptr, 0 As Long, ExtractIcon As Long End Function
When we no longer need the icon, and before we end our program, we must remove the icon from memory with a call to DestroyIcon. Here it is, wrapped in a Liberty BASIC function:
Sub DestroyIcon hIcon CallDLL #user32, "DestroyIcon",_ hIcon As Long,_ 'handle of icon ret As Boolean End Sub
Once we have a handle to an icon, we can display the icon. We use the DrawIcon function to display the icon on the specified Device Context, at the x, y location of our choice. Here it is, wrapped in a Liberty BASIC function:
Function DrawIcon(hdc,hIcon,x,y) CallDLL #user32, "DrawIcon",hdc As Long, x As Long,_ y As Long, hIcon As Long, DrawIcon As Long End Function
We could use the device context of a window or graphicbox when drawing the icon. We first get the handle of the window with LB's hwnd(#window) function, then we can get the Device context of a window with GetDC:
Function GetDC(hWindow) CallDLL #user32, "GetDC",_ hWindow As Long,_ 'handle of window GetDC As Ulong 'handle of device context End Function 'Before the program ends, we must ReleaseDC: Sub ReleaseDC hWindow, hDC CallDLL#user32,"ReleaseDC",_ hWindow As Long,_ 'window handle hDC As Long,_ 'handle of device context result As Long End Sub
We aren't drawing the icon on our window in this demo, however. We are going to create a bitmap in memory and draw the icon on a memory device context that contains the created bitmap. This way, we can save the bitmap easily with the BMPSAVE command. Before we can create a memory device context, we must use the GetDC function to get a device context handle to our window, as outlined above. With this, we can create a memory device context with CreateCompatibleDC. When it is no longer needed we must delete this memory device context with DeleteDC. Here are the functions:
Function CreateCompatibleDC(hDC) CallDLL #gdi32,"CreateCompatibleDC",_ hDC As Long,_ 'device context of window CreateCompatibleDC As Ulong 'returns memory device context End Function Sub DeleteDC hDC CallDLL #gdi32, "DeleteDC",_ hDC As Long,_ 'handle of memory device context r As Boolean End Sub
When it is created, the memory DC has a default bitmap that is one pixel wide
and one pixel high. We'll create our own bitmap in memory and make it 32x32,
the size of a standard icon. It is important to note that we must use a device
context handle for our window in this function and NOT the handle of the memory
device context:
Function CreateCompatibleBitmap(hDC,wide,high ) CallDLL #gdi32, "CreateCompatibleBitmap",_ hDC As Long,_ 'device context of WINDOW wide As Long,_ 'desired width of bitmap high As Long,_ 'desired height of bitmap CreateCompatibleBitmap As Ulong 'returns handle of memory bitmap End Function
Once we select the memory bitmap into the memory device context with SelectObject, all functions that write to the memory device context will write on the memory bitmap. The SelectObject function returns the handle to the previous (default) bitmap. We'll save this in our program, so that we can access it again later:
Function SelectObject(hDC,hObject) CallDLL #gdi32,"SelectObject",_ hDC As Long,_ 'handle of memory device context hObject As Long,_ 'handle of memory bitmap SelectObject As Long 'returns previously selected object End Function 'When we no longer need the bitmap in memory, we must delete it with DeleteObject: Sub DeleteObject hObject CallDLL #gdi32,"DeleteObject",_ hObject As Long,_ 'handle of memory bitmap r As Boolean End Sub
We need to give the memory bitmap a blank, white background each time we want to draw a new icon on it. We do this with a call to PatBlt. It requires the x, y position to begin and the width and height of the rectangle we want to draw on. It also requires a flag telling it what we want to do to that rectangle. Since we want to fill it with white, our flag will be _WHITENESS.
CallDLL #gdi32, "PatBlt",_ hDC As Long,_ 'handle of device context x As Long,_ 'upper left corner x coord y As Long,_ 'upper left corner y coord width As Long,_ 'rectangle width height As Long,_ 'rectangle height _WHITENESS As Ulong,_ 'fill with white r As Boolean
Now that we know all of the API functions, we can write the Liberty BASIC code to extract an icon from a disk file, draw it on a memory bitmap, then save that bitmap to disk with LB's BMPSAVE COMMAND.
We allow the user to choose a file that contains icons:
FileDialog "Open Icon","*.ico;*.exe;*.icl;*.dll",iconfile$
If iconfile$="" Then Wait
If we've extracted an icon previously, we remove it from memory:
If hMemIcon<>0 Then Call DestroyIcon hMemIcon
Now we extract the first icon from the diskfile, getting its handle into hMemIcon:
hMemIcon=ExtractIcon(hWnd(#1),iconfile$)
It is always good to check for errors:
If hMemIcon=0 Then
Notice "Cannot extract icon!"
Wait
End If
We need to clear our memory bitmap to a plain white background:
Call PatBlt hMemDC,0,0,32,32,_WHITENESS
Now we can draw the icon on the memory bitmap:
r=DrawIcon(hMemDC,hMemIcon,0,0)
We can display the memory bitmap in a graphicbox. IMPORTANT: we must first deselect the bitmap from the memory DC before we can load it with LOADBMP. We do this by selecting the original, default bitmap back into the memory DC:
hBitmap=SelectObject(hMemDC,oldBitmap)
Now we can load the bitmap using the LOADBMP command:
LoadBmp "IconBmp", hBitmap
Once we've loaded it, we can draw it with DRAWBMP. We can then UNLOADBMP on our LB bitmap to free the memory.
#1.g "down;cls;drawbmp IconBmp 0 0;flush"
UnloadBmp "IconBmp"
To prepare for the user's next icon choice, we select the memory bitmap back into the memory DC:
oldBitmap=SelectObject(hMemDC,hBitmap)
When the user chooses to save the icon as a bitmap, we'll first check to make
sure there is a valid icon to save:
If hMemIcon=0 Then
Notice "No icon to save."
Wait
End If
We'll query the user for a filename for the bitmap:
FileDialog "Save As","*.bmp",savefile$
If savefile$="" Then Wait
Remember that when we wanted to display the bitmap, we deselected it from the memory device context, and we must do that again so that we can load it with LOADBMP, then save it with BMPSAVE:
hBitmap=SelectObject(hMemDC,oldBitmap)
LoadBmp "IconBmp", hBitmap
BmpSave "IconBmp",savefile$
UnloadBmp "IconBmp"
That's everything! Here is the complete demo program:
=====================================
If Val(Version$)<3 Then Notice "Requires at least LB3." End End If NoMainWin Menu #1, "&File","&Open Icon",[openIcon],_ "&Save As Bitmap",[saveAsBitmap],_ |,"E&xit",[quit] Graphicbox #1.g, 50,50,34,34 Open "Save Icon As Bitmap" For Window_nf As #1 #1 "trapclose [quit]" #1.g "down" hWinDC=GetDC(hWnd(#1)) hMemDC=CreateCompatibleDC(hWinDC) hBitmap=CreateCompatibleBitmap(hWinDC,32,32) oldBitmap=SelectObject(hMemDC,hBitmap) Call PatBlt hMemDC,0,0,32,32,_WHITENESS Wait [quit] Call ReleaseDC hWnd(#1),hWinDC Call DeleteDC hMemDC Call DeleteObject hBitmap Call DestroyIcon hMemIcon Close #1:End [openIcon] FileDialog "Open Icon","*.ico;*.exe;*.icl;*.dll",iconfile$ If iconfile$="" Then Wait If hMemIcon<>0 Then Call DestroyIcon hMemIcon hMemIcon=ExtractIcon(hWnd(#1),iconfile$) If hMemIcon=0 Then Notice "Cannot extract icon!" Wait End If Call PatBlt hMemDC,0,0,32,32,_WHITENESS r=DrawIcon(hMemDC,hMemIcon,0,0) 'deselect bitmap from memory DC to load hBitmap=SelectObject(hMemDC,oldBitmap) LoadBmp "IconBmp", hBitmap #1.g "down;cls;drawbmp IconBmp 0 0;flush" UnloadBmp "IconBmp" 'select bitmap back into memory DC oldBitmap=SelectObject(hMemDC,hBitmap) Wait [saveAsBitmap] If hMemIcon=0 Then Notice "No icon to save." Wait End If FileDialog "Save As","*.bmp",savefile$ If savefile$="" Then Wait hBitmap=SelectObject(hMemDC,oldBitmap) LoadBmp "IconBmp", hBitmap BmpSave "IconBmp",savefile$ UnloadBmp "IconBmp" 'select bitmap back into memory DC oldBitmap=SelectObject(hMemDC,hBitmap) Wait ''''Subs and Functions: Function GetDC(hWnd) CallDLL #user32, "GetDC",hWnd As Long,_ GetDC As Ulong End Function Sub ReleaseDC hWnd, hDC CallDLL#user32,"ReleaseDC",hWnd As Long,_ hDC As Long,result As Long End Sub Function CreateCompatibleDC(hDC) CallDLL #gdi32,"CreateCompatibleDC",hDC As Long,_ CreateCompatibleDC As Ulong End Function Sub DeleteDC hDC CallDLL #gdi32, "DeleteDC",hDC As Long,_ r As Boolean End Sub Function CreateCompatibleBitmap(hDC,w,h ) CallDLL #gdi32, "CreateCompatibleBitmap",_ hDC As Long,w As Long,h As Long,_ CreateCompatibleBitmap As Ulong End Function Function SelectObject(hDC,hObject) CallDLL #gdi32,"SelectObject",hDC As Long,_ hObject As Long,SelectObject As Long 'returns previously selected object End Function Sub DeleteObject hObject CallDLL #gdi32,"DeleteObject",hObject As Long,_ r As Boolean End Sub Function GetWindowLong(hW, type) CallDLL #user32, "GetWindowLongA",_ hW As Long, type As Long,GetWindowLong As Long End Function Function ExtractIcon(hW, file$) hInst=GetWindowLong(hW, _GWL_HINSTANCE) CallDLL #shell32, "ExtractIconA",hInst As Long,_ file$ As Ptr, 0 As Long, ExtractIcon As Long End Function Function DrawIcon(hdc,hIcon,x,y) CallDLL #user32, "DrawIcon",hdc As Long, x As Long,_ y As Long, hIcon As Long, DrawIcon As Long End Function Sub DestroyIcon hIcon CallDLL #user32, "DestroyIcon",_ hIcon As Long,_ 'handle of icon ret As Boolean End Sub Sub PatBlt hDC,x,y,w,h,flag CallDLL #gdi32, "PatBlt",hDC As Long,_ x As Long,y As Long,w As Long,h As Long,_ flag As Ulong,r As Boolean End Sub
Maintaining checkbox states
Tidbits from the community
Liberty Basic 4
New Alternate Forum
Using the Tsunami Database
Wizard Framework
Links to LB Sites
Update on 10th Anniversary Contest
Extracting Icons And Saving Them As Bitmaps
Applying Symbolic Logic
QuadClicks
Simple Math For Moving Objects
Event Driven Programming - Part 2
The Beginners Series - Part 1