The program illustrated here is a modified version of sysinfo.exw, from Lesson 16, with two major differences.
First, the information is displayed through a pixmap. This is being used as a buffer to hold the updated information, which is then all sent to the program's window at once. Doing this stops the screen from 'flickering' as much as it did in the original program.
When this program is first started up, it will be minimized, and it's program icon will be placed in the System Tray, as a little 'question mark'. ( usually near the speaker and time display. )
Left-clicking on the icon will simply
show the program's normal window. The three buttons will allow:
1)
- hiding the program window again,
2) - shutting it down
altogether, or,
3) - opening a normal ( About ) message box.
This example also illustrates the
Win32Lib wrappers you can use to declare and manipulate Win32
structures. Instead of using allocate(), peek(), poke(), etc.,
Win32Lib has some 'wrapped' functions to make this a little easier,
since these 'wrappers' will automatically allocate the correct amount
of memory, based on their type.
( Byte, Word, DWord,
zero-terminated string, etc. )
--
sysinfo2.exw
-- dynamically displays information, with it's icon in the System Tray.
include win32lib.ew
without warning
object ok
-- what follows is the 'TrayIcon' code --
-- originally 'wrapped' by Hendrik Mundt. --
constant
Shell_NotifyIconA__ = registerw32Function(shell32,"Shell_NotifyIconA", {C_LONG, C_POINTER}, C_INT ),
zNIM_ADD = 0,
zNIM_MODIFY = 1,
zNIM_DELETE = 2,
zNIF_MESSAGE = 1,
zNIF_ICON = 2,
zNIF_TIP = 4,
zWM_USER = #400,
zUWM_SYSTRAY = zWM_USER + 1
-- declare memory required for NOTIFYICONDATA structure
constant
NIDcbSize = allot( DWord ),
NIDhWnd = allot( Long ),
NIDuID = allot( Long ),
NIDuFlags = allot( Long ),
NIDuCallbackMessage = allot( Long ),
NIDhIcon = allot( DWord ),
NIDszTip = allot( 64 ),
SIZE_OF_NOTIFYICONDATA = allotted_size()
function AddTrayIcon(atom hwnd,integer uid,atom hicon,sequence tooltip)
atom nid
-- allocate memory for required structure
nid = acquire_mem( 0,SIZE_OF_NOTIFYICONDATA )
-- and fill it with the required information
store( nid, NIDcbSize, SIZE_OF_NOTIFYICONDATA )
store( nid, NIDhWnd, hwnd )
store( nid, NIDuID, uid )
store( nid, NIDuFlags, or_all({ zNIF_MESSAGE,zNIF_ICON,zNIF_TIP} ))
store( nid, NIDuCallbackMessage, zUWM_SYSTRAY )
store( nid, NIDhIcon, hicon )
store( nid, NIDszTip, tooltip )
ok = w32Func(Shell_NotifyIconA__, {zNIM_ADD, nid} )
release_mem( nid )
return ok
end function
function DelTrayIcon(atom hwnd, integer uid)
atom nid
nid = acquire_mem( 0,SIZE_OF_NOTIFYICONDATA )
store( nid, NIDcbSize, SIZE_OF_NOTIFYICONDATA )
store( nid, NIDhWnd, hwnd )
store( nid, NIDuID, uid )
ok = w32Func( Shell_NotifyIconA__, {zNIM_DELETE, nid} )
release_mem( nid )
return ok
end function
-- end of TrayIcon 'wrapper' --
sequence size
-- our main window and it's buttons.
constant
MemWin = create( Window, "- System Info -", 0, Default, Default, 480, 175, {WS_DLGFRAME} ),
Button1 = create( PushButton, "Close", MemWin, 65, 123, 80, 25, 0 ),
Button2 = create( PushButton, "Kill", MemWin, 180, 123, 80, 25, 0 ),
Button3 = create( PushButton, "About", MemWin, 295, 123, 80, 25, 0 ),
-- links to procedures in kernel32.dll
zGlobalMemoryStatus = registerw32Procedure( kernel32, "GlobalMemoryStatus", {C_POINTER} ),
zGetWindowsDirectory = registerw32Procedure( kernel32, "GetWindowsDirectoryA", {C_POINTER, C_INT} ),
zGetCurrentDirectory = registerw32Function( kernel32, "GetCurrentDirectoryA", {C_INT, C_POINTER}, C_INT ),
zGetCurrentTime = registerw32Procedure( kernel32, "GetLocalTime", {C_POINTER} )
-- let's calculate our pixmap size, based on the client
-- area left in our main window, and subtract 30 from the 'y' dimension
-- to leave us room for the buttons.
size = getClientRect(MemWin)
constant
Buffer = create( Pixmap, "", 0, 0, 0, size[3]-size[1], size[4]-size[2]-30, 0 ),
MyTimer = 1
-- easy on the eyes...
setFont(Buffer,"System",10,1)
-- some 'hints' for the buttons, in my 'pathetic' German.
setHint(Button1,"Fluoreszenzunterdrükkung ;-)")
setHint(Button2,"Stoppanweisung")
setHint(Button3,"...kann nicht in einer Stellung stehenbleiben!")
The next four blocks of code, are all the routines which get the information to be displayed in the main window.
sequence meminfo, windirstring, currentdirstring
atom buffer
procedure GetMemory()
buffer = allocate(32)
poke4(buffer,32)
w32Proc(zGlobalMemoryStatus,{buffer})
meminfo = peek4u({buffer,8})
free(buffer)
end procedure
function GetWindowsDir()
sequence WinDir
integer i
buffer = allocate(100)
w32Proc(zGetWindowsDirectory, {buffer, 100})
WinDir = ""
i = 0
while peek(buffer+i) != 0 do
WinDir = WinDir & peek(buffer+i)
i = i+1
end while
free(buffer)
return WinDir
end function
function GetCurrentDir()
sequence CurrentDir
integer i
buffer = allocate(4) -- first get the length using this dummy length.
i=w32Func(zGetCurrentDirectory, {4, buffer})
if i=0 then
ok = message_box( "Couldn't link to C function GetCurrentDirectoryA",
"Win32 Error", MB_ICONHAND+MB_TASKMODAL )
free(buffer)
abort(1)
end if
free(buffer)
buffer = allocate(i) -- do it again, with the correct length this time!
i=w32Func(zGetCurrentDirectory, {i, buffer})
CurrentDir = ""
i = 0
while peek(buffer+i) != 0 do
CurrentDir = CurrentDir & peek(buffer+i)
i = i+1
end while
free(buffer)
return CurrentDir
end function
function Getcurrenttime()
sequence currenttime
buffer = allocate(16)
w32Proc(zGetCurrentTime, {buffer})
currenttime = ""
for i = 0 to 15 do
currenttime = currenttime & peek(buffer+i)
end for
free(buffer)
return currenttime
end function
The following refresh_info() routine is responsible for writing all the information into our pixmap buffer, and then writing the whole pixmap out to the program's main window every second.
procedure refresh_info( integer self, integer event, sequence params )
sequence s, t, string1
-- first let's clear the buffer pixmap by painting over it.
setPenColor(Buffer,getSysColor( COLOR_BTNFACE ))
drawRectangle(Buffer,1,0,0,size[3]-size[1],size[4]-size[2]-30)
-- then write out our time string.
s=Getcurrenttime()
t=sprintf("%02d",s[9..10]) & ":" & sprintf("%02d",s[11.12])
& ":" & sprintf("%02d",s[13..14])
setPenPos(Buffer,2,2)
wPuts(Buffer,"current time = " & t )
-- ...then our memory info...
GetMemory()
setPenPos(Buffer,2,20)
string1= "bytes of memory = " & sprintf("%d",meminfo[3])
wPuts(Buffer,string1)
setPenPos(Buffer,2,38)
string1= "percent of memory in use = " & sprintf("%d",meminfo[2]) & "%"
wPuts(Buffer,string1 & " - including 'virtual' memory.")
setPenPos(Buffer,2,56)
string1= "free memory bytes = " & sprintf("%d",meminfo[4])
wPuts(Buffer,string1)
-- then, write out our directory info...
setPenPos(Buffer,2,74)
wPuts(Buffer,"Windows dir = " & windirstring)
setPenPos(Buffer,2,92)
wPuts(Buffer,"this program's dir = " & currentdirstring)
copyBlt( MemWin, 0, 0, Buffer )
end procedure
The next five procedures are all the event handlers for everything but the onTimer[] event, which is above.
procedure onOpen_MemWin( integer self, integer event, sequence params )
-- put it's icon in the System Tray
-- note, for this simple example,
-- we're using the 'stock' IDI_QUESTION icon.
ok = AddTrayIcon( getHandle(MemWin),1,
w32Func( xLoadIcon, { NULL, IDI_QUESTION } ),
"System Information" ) -- our app. name in the tooltip.
-- this is our re-fresh interval timer.
setTimer(MemWin, MyTimer, 1000)
-- since the following is 'static', we only get it once.
windirstring = GetWindowsDir()
currentdirstring=GetCurrentDir()
end procedure
procedure hide_MemWin( integer self, integer event, sequence params )
setVisible(MemWin,False)
end procedure
procedure kill_MemWin( integer self, integer event, sequence params )
-- since we're leaving, remove the program's icon.
ok = DelTrayIcon( getHandle(MemWin), 1 )
closeWindow(MemWin)
end procedure
procedure about( integer self, integer event, sequence params )
ok = message_box( "An application running from the SystemTray,\n" &
"with code contributed by Hendrik Mundt.\n\n" &
"Using Win32lib.ew, by David Cuny and Friends.",
"... a Win32 Tutorial",#2000)
end procedure
procedure onEvenr_MemWin( integer self, integer event, sequence params )
integer lParam = params[1] -- maybe
if lParam = WM_LBUTTONUP then
setVisible( MemWin, True )
ok = w32Func( xSetForegroundWindow,{getHandle(MemWin)})
end if
end procedure
setHandler( MemWin, w32HOpen, routine_id("onOpen_MemWin") )
setHandler( MemWin, w32HTimer, routine_id("refresh_info") )
setHandler( Button1, w32HClick, routine_id("hide_MemWin") )
setHandler( Button2, w32HClick, routine_id("kill_MemWin") )
setHandler( Button3, w32HClick, routine_id("about") )
setHandler( MemWin, w32HEvent, routine_id("onEvent_MemWin") )
-- WinMain(MemWin,WS_MINIMIZE) -- if I do this, program vanishes into space!
WinMain(MemWin,Normal)
----
For some 'magical' reason this program's icon seems to disappear in about 10 seconds even if it's not removed on program exit, but it's better to be safe than sorry...
This program could be simplified by declaring 'nid' only once outside of the two functions, and removing the ( release_mem( nid ) ) call from AddTrayIcon().
This would simplify the DelTrayIcon() function to only this:
function DelTrayIcon(atom hwnd, integer uid)
ok = w32Func( Shell_NotifyIconA__, {zNIM_DELETE, nid} )
release_mem( nid )
return ok
end function
...and there's more ;-)
...since hwnd,
and uid, are not really required any more, when calling
DelTrayIcon().
...end...