Adding Menu Items to the System Menu

The System Menu, ( also called the window menu, or control menu ) is accessed by the user when the program icon is 'clicked', or the [ ALT SPACE ] keyboard combination is used.

The following example will show you how to add your own menu items to this, and how to handle the messages which Windows sends to your application if any of these items are 'selected' by the user.

.

-- system-menu.exw

-- Simple timer,  and a trick system menu !

include win32lib.ew
without warning

atom jk
integer ticks
ticks = 0

constant
zWM_SYSCOMMAND = 274, 

SysMenu_Reset = WM_USER + 100,  -- your two user defined messages
SysMenu_About = WM_USER + 101, 

PWin = create( Window, "<< SYSTEM-MENU", 0, Default, Default, 250, 120, 0 ), 
note = create( LText, "^^ Click on the program's icon!", PWin, 3, 3, 230, 20, 0 ), 
timerdisp = create( RText, "0", PWin, 10, 30, 225, 42, 0 ), 
MyTimer = 1

setFont( note, "Arial", 10, or_all( {Bold, Italic} ) )
setFont( timerdisp, "Arial", 28, Bold )

-- the next two functions access our program's system menu.

function GetSystemMenu( atom hWnd,  atom bRevert )
  return w32Func( xGetSystemMenu, {hWnd, bRevert} )
end function

function AppendMenu( atom hmenu, sequence new_item ) 
atom ptr
  ptr = allocate_string( new_item[3] )
  return  w32Func( xAppendMenu, {hmenu, new_item[1], new_item[2], ptr} )
  free( ptr )
end function

atom hSysMenu

-- get the handle of this program's system menu,
hSysMenu = GetSystemMenu( getHandle( PWin ), 0 )
-- then add a separator, and 2 new items to the system menu
jk = AppendMenu( hSysMenu, {MF_SEPARATOR, 0, ""} )
jk = AppendMenu( hSysMenu, {MF_STRING, SysMenu_Reset, "Reset count"} )
jk = AppendMenu( hSysMenu, {MF_STRING, SysMenu_About, "What's this?"} )

-- update our timer display every second.
procedure onTimer_PWin(  integer self,  integer event,  sequence params  )
  ticks = ticks + 1
  setText( timerdisp, sprintf( "%d", {ticks} ) )
end procedure  

procedure onOpen_PWin(  integer self,  integer event,  sequence params  )
  setTimer(  PWin,  MyTimer,  1000  )
end procedure

procedure about()
jk = message_box(  "A simple timer demo, \n\n" &
  "with two added items in the system menu.\n" &
  "-- using code originally by Jacques Deschênes --", 
  "... a Win32 Tutorial about 'messages'.", #2000 )
end procedure

procedure reset()
  killTimer( PWin, MyTimer )
  ticks=0
  setText( timerdisp, sprintf( "%d", {ticks} ) )
  setTimer(  PWin,  MyTimer,  1000  )
end procedure

-- and here's our private event handler,
-- which tells our program what to do when it
-- receives a zWM_SYSCOMMAND message from Windows,
-- with our user defined message in the low word of wParam.
procedure onEvent_PWin(  integer self,  integer event,  sequence params  )
atom cmd
    event = params[1]    -- cheat old code
    atom wParam = params[2]

    if event = zWM_SYSCOMMAND then  -- *this
        -- use only low word of wParam, just in case...
        cmd = lo_word( wParam )
        if cmd = SysMenu_About then
            about()
        elsif cmd = SysMenu_Reset then
            reset()
        end if
    end if  -- *and this
    
end procedure

--

setHandler(  PWin,  w32HOpen,  routine_id(  "onOpen_PWin"  )  )
setHandler(  PWin,  w32HTimer,  routine_id(  "onTimer_PWin"  )  )
setHandler(  PWin,  w32HEvent,  routine_id(  "onEvent_PWin"  )  )

WinMain( PWin, Normal )
-----------

If you want to understand a bit more about handling Windows messages, try commenting out the two lines marked in red above, in the program's code. If you do so, notice what happens when your 'mouse' cursor moves over either of the two system menu items which have been added to this program. No 'clicking' required !

I should point out that any private messages your programs use should be between WM_USER, ( #400 ), and #7FFF, since all other values are reserved for use by Windows itself.
( ... with apparently, some further restrictions ? ...if your button or other control suddenly doesn't work, you've probably found one. )

..end of lesson.

CONTENTS