File: n_icontray.sru
Size: 19469
Date: Wed, 09 Jan 2019 02:54:04 +0100
$PBExportHeader$n_icontray.sru
$PBExportComments$Icon System Tray functions
forward
global type n_icontray from nonvisualobject
end type
type guid from structure within n_icontray
end type
type notifyicondata from structure within n_icontray
end type
type dllversioninfo from structure within n_icontray
end type
end forward

type guid from structure
   unsignedlong      data1
   integer     data2
   integer     data3
   byte     data4[8]
end type

type notifyicondata from structure
   unsignedlong      cbsize
   longptr     hwnd
   unsignedlong      uid
   unsignedlong      uflags
   unsignedlong      ucallbackmessage
   longptr     hicon
   character      sztip[128]
   unsignedlong      dwstate
   unsignedlong      dwstatemask
   character      szinfo[256]
   unsignedlong      utimeout
   character      szinfotitle[64]
   unsignedlong      dwinfoflags
   guid     guiditem
   longptr     hballoonicon
end type

type dllversioninfo from structure
   unsignedlong      cbsize
   unsignedlong      dwmajorversion
   unsignedlong      dwminorversion
   unsignedlong      dwbuildnumber
   unsignedlong      dwplatformid
end type

global type n_icontray from nonvisualobject autoinstantiate
end type

type prototypes
Function boolean Shell_NotifyIcon ( &
   ulong dwMessage, &
   Ref NOTIFYICONDATA lpData &
   ) Library "shell32.dll" alias for "Shell_NotifyIconW"

Function boolean SetForegroundWindow ( &
   longptr hWnd &
   ) Library "user32.dll"

Function longptr LoadImage ( &
   longptr hInst, &
   string lpszName, &
   ulong uType, &
   long cxDesired, &
   long cyDesired, &
   ulong fuLoad &
   ) Library "user32.dll" Alias For "LoadImageW"

Function longptr ExtractIcon ( &
   longptr hInst, &
   string lpszExeFileName, &
   ulong nIconIndex &
   ) Library "shell32.dll" Alias For "ExtractIconW"

Function boolean DestroyIcon ( &
   longptr hIcon &
   ) Library "user32.dll"

Function boolean RegisterHotKey ( &
   longptr hWnd, &
   long id, &
   ulong fsModifiers, &
   ulong vk &
   ) Library "user32.dll"

Function boolean UnregisterHotKey ( &
   longptr hWnd, &
   long id &
   ) Library "user32.dll"

Subroutine DllGetVersion ( &
   Ref DLLVERSIONINFO pdvi &
   ) Library "comctl32.dll" alias for "DllGetVersion;Ansi"

Function longptr LoadLibrary ( &
   string lpFileName &
   ) Library "kernel32.dll" Alias For "LoadLibraryW"

Function boolean FreeLibrary ( &
   longptr hModule &
   ) Library "kernel32.dll"

Function longptr GetProcAddress ( &
   longptr hModule, &
   string lpProcName &
   ) Library "kernel32.dll" alias for "GetProcAddress;Ansi"

Subroutine DebugMsg( &
   String lpOutputString &
   ) Library "kernel32.dll" Alias For "OutputDebugStringW"

end prototypes

type variables
Longptr iptr_iconhandles[]

// actual values set in constructor event
Long NOTIFYICONDATA_SIZE = 88
Long NOTIFYICON_VERSION = 1

// function Constants

Constant long NIF_MESSAGE     = 1
Constant long NIF_ICON        = 2
Constant long NIF_TIP         = 4
Constant long NIF_STATE       = 8
Constant long NIF_INFO        = 16
Constant long NIF_GUID        = 32
Constant long NIF_REALTIME    = 64
Constant long NIF_SHOWTIP     = 128

Constant long NIM_ADD         = 0
Constant long NIM_MODIFY      = 1
Constant long NIM_DELETE      = 2
Constant long NIM_SETFOCUS    = 3
Constant long NIM_SETVERSION  = 4
Constant long NIM_VERSION     = 5

Constant long NIS_HIDDEN      = 1
Constant long NIS_SHAREDICON  = 2

Constant long NIIF_NONE       = 0
Constant long NIIF_INFO       = 1
Constant long NIIF_WARNING    = 2
Constant long NIIF_ERROR      = 3
Constant long NIIF_USER       = 4
Constant long NIIF_ICON_MASK  = 15
Constant long NIIF_NOSOUND    = 16
Constant long NIIF_LARGE_ICON = 32
Constant long NIIF_RESPECT_QUIET_TIME = 64

Constant long WM_USER = 1024
Constant long PBM_CUSTOMEVENT       = (WM_USER - 1) + 1
Constant long NIN_SELECT            = WM_USER + 0
Constant long NIN_BALLOONSHOW       = WM_USER + 2
Constant long NIN_BALLOONHIDE       = WM_USER + 3
Constant long NIN_BALLOONTIMEOUT    = WM_USER + 4
Constant long NIN_BALLOONUSERCLICK  = WM_USER + 5
Constant long NIN_POPUPOPEN         = WM_USER + 6
Constant long NIN_POPUPCLOSE        = WM_USER + 7

Constant ulong NOTIFYICONDATA_V1_SIZE = 88  // pre-5.0 structure size
Constant ulong NOTIFYICONDATA_V2_SIZE = 488 // pre-6.0 structure size
Constant ulong NOTIFYICONDATA_V3_SIZE = 504 // 6.0 structure size
Constant ulong NOTIFYICONDATA_V4_SIZE = 508 // Vista and newer structure size

Constant long ICON_SMALL         = 0
Constant long ICON_BIG           = 1

Constant ulong IMAGE_BITMAP      = 0
Constant ulong IMAGE_ICON        = 1
Constant ulong IMAGE_CURSOR      = 2

Constant ulong LR_LOADFROMFILE   = 16
Constant ulong LR_DEFAULTSIZE    = 64

// windows messages
Constant long WM_GETICON         = 127
Constant long WM_MOUSEMOVE       = 512
Constant long WM_LBUTTONDOWN     = 513
Constant long WM_LBUTTONUP       = 514
Constant long WM_LBUTTONDBLCLK   = 515
Constant long WM_RBUTTONDOWN     = 516
Constant long WM_RBUTTONUP       = 517
Constant long WM_RBUTTONDBLCLK   = 518

// hotkey values
Constant ulong MOD_NONE          = 0
Constant ulong MOD_ALT           = 1
Constant ulong MOD_CONTROL       = 2
Constant ulong MOD_SHIFT         = 4
Constant ulong MOD_WIN           = 8
Ulong iul_keycode = 0
Ulong iul_modifier = 0

// virtual keycodes
Constant ulong KeyBack           = 8
Constant ulong KeyTab            = 9
Constant ulong KeyEnter          = 13
Constant ulong KeyShift          = 16
Constant ulong KeyControl        = 17
Constant ulong KeyAlt            = 18
Constant ulong KeyPause          = 19
Constant ulong KeyCapsLock       = 20
Constant ulong KeyEscape         = 27
Constant ulong KeySpaceBar       = 32
Constant ulong KeyPageUp         = 33
Constant ulong KeyPageDown       = 34
Constant ulong KeyEnd            = 35
Constant ulong KeyHome           = 36
Constant ulong KeyLeftArrow      = 37
Constant ulong KeyUpArrow        = 38
Constant ulong KeyRightArrow     = 39
Constant ulong KeyDownArrow      = 40
Constant ulong KeyPrintScreen    = 44
Constant ulong KeyInsert         = 45
Constant ulong KeyDelete         = 46
Constant ulong Key0              = 48
Constant ulong Key1              = 49
Constant ulong Key2              = 50
Constant ulong Key3              = 51
Constant ulong Key4              = 52
Constant ulong Key5              = 53
Constant ulong Key6              = 54
Constant ulong Key7              = 55
Constant ulong Key8              = 56
Constant ulong Key9              = 57
Constant ulong KeyA              = 65
Constant ulong KeyB              = 66
Constant ulong KeyC              = 67
Constant ulong KeyD              = 68
Constant ulong KeyE              = 69
Constant ulong KeyF              = 70
Constant ulong KeyG              = 71
Constant ulong KeyH              = 72
Constant ulong KeyI              = 73
Constant ulong KeyJ              = 74
Constant ulong KeyK              = 75
Constant ulong KeyL              = 76
Constant ulong KeyM              = 77
Constant ulong KeyN              = 78
Constant ulong KeyO              = 79
Constant ulong KeyP              = 80
Constant ulong KeyQ              = 81
Constant ulong KeyR              = 82
Constant ulong KeyS              = 83
Constant ulong KeyT              = 84
Constant ulong KeyU              = 85
Constant ulong KeyV              = 86
Constant ulong KeyW              = 87
Constant ulong KeyX              = 88
Constant ulong KeyY              = 89
Constant ulong KeyZ              = 90
Constant ulong KeyLeftWindows    = 91
Constant ulong KeyRightWindows   = 92
Constant ulong KeyApps           = 93
Constant ulong KeyNumPad0        = 96
Constant ulong KeyNumPad1        = 97
Constant ulong KeyNumPad2        = 98
Constant ulong KeyNumPad3        = 99
Constant ulong KeyNumPad4        = 100
Constant ulong KeyNumPad5        = 101
Constant ulong KeyNumPad6        = 102
Constant ulong KeyNumPad7        = 103
Constant ulong KeyNumPad8        = 104
Constant ulong KeyNumPad9        = 105
Constant ulong KeyMultiply       = 106
Constant ulong KeyAdd            = 107
Constant ulong KeySubtract       = 109
Constant ulong KeyDecimal        = 110
Constant ulong KeyDivide         = 111
Constant ulong KeyF1             = 112
Constant ulong KeyF2             = 113
Constant ulong KeyF3             = 114
Constant ulong KeyF4             = 115
Constant ulong KeyF5             = 116
Constant ulong KeyF6             = 117
Constant ulong KeyF7             = 118
Constant ulong KeyF8             = 119
Constant ulong KeyF9             = 120
Constant ulong KeyF10            = 121
Constant ulong KeyF11            = 122
Constant ulong KeyF12            = 123
Constant ulong KeyNumLock        = 144
Constant ulong KeyScrollLock     = 145
Constant ulong KeySemiColon      = 186
Constant ulong KeyEqual          = 187
Constant ulong KeyComma          = 188
Constant ulong KeyDash           = 189
Constant ulong KeyPeriod         = 190
Constant ulong KeySlash          = 191
Constant ulong KeyBackQuote      = 192
Constant ulong KeyLeftBracket    = 219
Constant ulong KeyBackSlash      = 220
Constant ulong KeyRightBracket   = 221
Constant ulong KeyQuote          = 222

end variables

forward prototypes
public subroutine of_setfocus (window aw_window)
public function boolean of_modify_icon (window aw_window, string as_imagename, unsignedinteger aui_index)
public function boolean of_modify_icon (window aw_window, string as_imagename)
public function boolean of_add_icon (window aw_window)
public function boolean of_add_icon (window aw_window, string as_imagename)
public function boolean of_modify_tip (window aw_window, string as_newtip)
public function boolean of_unregisterhotkey (window aw_window, integer ai_hotkeyid)
public function boolean of_ishotkey (unsignedlong wparam, long lparam)
public function boolean of_delete_icon (window aw_window, boolean ab_show)
public function integer of_dllversion ()
public function boolean of_trayfocus ()
public function boolean of_balloon_tip (window aw_window, string as_title, string as_info)
public function boolean of_balloon_tip (window aw_window, string as_title, string as_info, icon dwinfoflag)
private function longptr of_loadimage (string as_imagename)
private function long of_loadimage (string as_filename, unsignedlong aul_iconindex)
public function boolean of_registerhotkey (window aw_window, long al_hotkeyid, unsignedlong aul_modifier, unsignedlong aul_keycode)
public function boolean of_add_icon (window aw_window, string as_imagename, unsignedlong aul_index)
public function boolean of_balloon_tip (window aw_window, string as_title, string as_info, unsignedlong aul_timeout, icon dwinfoflag)
end prototypes

public subroutine of_setfocus (window aw_window);// give window proper focus

Longptr hWnd

hWnd = Handle(aw_window)

SetForegroundWindow(hWnd)

end subroutine

public function boolean of_modify_icon (window aw_window, string as_imagename, unsignedinteger aui_index);// modify icon in the system tray

NOTIFYICONDATA lstr_NID

// populate structure
lstr_NID.cbSize   = NOTIFYICONDATA_SIZE
lstr_NID.hWnd     = Handle(aw_window)
lstr_NID.uID      = 1
lstr_NID.uFlags   = NIF_ICON
lstr_NID.hIcon = this.of_LoadImage(as_imagename, aui_index)

If lstr_NID.hIcon = 0 Then Return False

// modify icon in system tray
Return Shell_NotifyIcon(NIM_MODIFY, lstr_NID)

end function

public function boolean of_modify_icon (window aw_window, string as_imagename);// modify icon in the system tray

NOTIFYICONDATA lstr_NID

// populate structure
lstr_NID.cbSize   = NOTIFYICONDATA_SIZE
lstr_NID.hWnd     = Handle(aw_window)
lstr_NID.uID      = 1
lstr_NID.uFlags   = NIF_ICON
lstr_NID.hIcon = this.of_LoadImage(as_imagename)

// modify icon in system tray
Return Shell_NotifyIcon(NIM_MODIFY, lstr_NID)

end function

public function boolean of_add_icon (window aw_window);// add window icon to the system tray

NOTIFYICONDATA lstr_NID

// populate structure
lstr_NID.cbSize   = NOTIFYICONDATA_SIZE
lstr_NID.hWnd     = Handle(aw_window)
lstr_NID.uID      = 1
lstr_NID.uFlags   = NIF_ICON + NIF_TIP + NIF_MESSAGE + NIF_SHOWTIP
lstr_NID.uCallBackMessage = PBM_CUSTOMEVENT
lstr_NID.hIcon    = Send(lstr_NID.hWnd, WM_GETICON, ICON_SMALL, 0)
lstr_NID.szTip    = aw_window.title

// add icon to system tray
If Shell_NotifyIcon(NIM_ADD, lstr_NID) Then
   // make window invisible
   aw_window.Hide()
   Return True
Else
   Return False
End If

end function

public function boolean of_add_icon (window aw_window, string as_imagename);// add loaded icon to the system tray

NOTIFYICONDATA lstr_NID

// populate structure
lstr_NID.cbSize   = NOTIFYICONDATA_SIZE
lstr_NID.hWnd     = Handle(aw_window)
lstr_NID.uID      = 1
lstr_NID.uFlags   = NIF_ICON + NIF_TIP + NIF_MESSAGE + NIF_SHOWTIP
lstr_NID.uCallBackMessage = PBM_CUSTOMEVENT
lstr_NID.hIcon    = this.of_LoadImage(as_imagename)
lstr_NID.szTip    = aw_window.title

// add icon to system tray
If Shell_NotifyIcon(NIM_ADD, lstr_NID) Then
   // make window invisible
   aw_window.Hide()
   Return True
Else
   Return False
End If

end function

public function boolean of_modify_tip (window aw_window, string as_newtip);// modify window icon tip in the system tray

NOTIFYICONDATA lstr_NID

// populate structure
lstr_NID.cbSize   = NOTIFYICONDATA_SIZE
lstr_NID.hWnd     = Handle(aw_window)
lstr_NID.uID      = 1
lstr_NID.uFlags   = NIF_TIP + NIF_SHOWTIP
lstr_NID.szTip = as_newtip

// modify icon tip
Return Shell_NotifyIcon(NIM_MODIFY, lstr_NID)

end function

public function boolean of_unregisterhotkey (window aw_window, integer ai_hotkeyid);// unregister a system wide hotkey
Return UnregisterHotKey(Handle(aw_window), ai_hotkeyid)

end function

public function boolean of_ishotkey (unsignedlong wparam, long lparam);// return whether this is a WM_HOTKEY event
// called from window 'Other' event

If wparam = 1 Then
   If IntHigh(lparam) = iul_keycode Then
      If IntLow(lparam)  = iul_modifier Then
         Return True
      End If
   End If
End If

Return False

end function

public function boolean of_delete_icon (window aw_window, boolean ab_show);// delete window icon from the system tray

NOTIFYICONDATA lstr_NID

// populate structure
lstr_NID.cbSize   = NOTIFYICONDATA_SIZE
lstr_NID.hWnd     = Handle(aw_window)
lstr_NID.uID      = 1

If ab_show Then
   // make window visible
   aw_window.Show()
   // give the window primary focus
   this.of_SetFocus(aw_window)
End If

// remove icon from system tray
Return Shell_NotifyIcon(NIM_DELETE, lstr_NID)

end function

public function integer of_dllversion ();// determine NOTIFYICONDATA version to use

DLLVERSIONINFO lstr_dvi
String ls_libname, ls_function
Integer li_version
Longptr ll_module, ll_rc

// default to original
li_version = 1

ls_libname  = "comctl32.dll"
ls_function = "DllGetVersion"

ll_module = LoadLibrary(ls_libname)
If ll_module > 0 Then
   ll_rc = GetProcAddress(ll_module, ls_function)
   If ll_rc > 0 Then
      lstr_dvi.cbSize = 20
      DllGetVersion(lstr_dvi)
      CHOOSE CASE lstr_dvi.dwMajorVersion
         CASE 6
            If lstr_dvi.dwMinorVersion = 0 Then
               li_version = 3
            Else
               li_version = 4
            End If
         CASE 5
            li_version = 2
         CASE ELSE
            li_version = 1
      END CHOOSE
   End If
   FreeLibrary(ll_module)
End If

Return li_version

end function

public function boolean of_trayfocus ();// give focus to the system tray

NOTIFYICONDATA lstr_NID

// populate structure
lstr_NID.cbSize = NOTIFYICONDATA_SIZE

// give focus to the system tray
Return Shell_NotifyIcon(NIM_SETFOCUS, lstr_NID)

end function

public function boolean of_balloon_tip (window aw_window, string as_title, string as_info);// create balloon tip in the system tray
// Note: to close a balloon tip, call with as_info an empty string

Return of_Balloon_Tip(aw_window, as_title, as_info, 0, None!)

end function

public function boolean of_balloon_tip (window aw_window, string as_title, string as_info, icon dwinfoflag);// create balloon tip in the system tray using a messagebox icon
// Note: to close a balloon tip, call with as_info an empty string

Return of_Balloon_Tip(aw_window, as_title, as_info, 0, dwInfoFlag)

end function

private function longptr of_loadimage (string as_imagename);// load image into memory from .ico, .cur or .ani file

Longptr lptr

CHOOSE CASE Lower(Right(as_imagename, 4))
   CASE ".ico"
      lptr = LoadImage(0, as_imagename, IMAGE_ICON, 0, 0, LR_LOADFROMFILE + LR_DEFAULTSIZE)
   CASE ".cur", ".ani"
      lptr = LoadImage(0, as_imagename, IMAGE_CURSOR, 0, 0, LR_LOADFROMFILE + LR_DEFAULTSIZE)
   CASE ELSE
END CHOOSE

Return lptr

end function

private function long of_loadimage (string as_filename, unsignedlong aul_iconindex);// load icon into memory from .exe or .dll file
// aui_iconindex is zero based (first icon is 0, second is 1)

Longptr lptr

// load icon
lptr = ExtractIcon(Handle(GetApplication()), as_filename, aul_iconindex)

// save handle for destroy in destructor event
If lptr > 0 Then
   iptr_iconhandles[UpperBound(iptr_iconhandles) + 1] = lptr
End If

Return lptr

end function

public function boolean of_registerhotkey (window aw_window, long al_hotkeyid, unsignedlong aul_modifier, unsignedlong aul_keycode);Longptr hWnd

hWnd = Handle(aw_window)

// remember hotkey info
iul_keycode  = aul_keycode
iul_modifier = aul_modifier

// register a system wide hotkey
Return RegisterHotKey(hWnd, al_hotkeyid, aul_modifier, aul_keycode)

end function

public function boolean of_add_icon (window aw_window, string as_imagename, unsignedlong aul_index);// add loaded icon to the system tray

NOTIFYICONDATA lstr_NID

// populate structure
lstr_NID.cbSize   = NOTIFYICONDATA_SIZE
lstr_NID.hWnd     = Handle(aw_window)
lstr_NID.uID      = 1
lstr_NID.uFlags   = NIF_ICON + NIF_TIP + NIF_MESSAGE + NIF_SHOWTIP
lstr_NID.uCallBackMessage = PBM_CUSTOMEVENT
lstr_NID.hIcon    = this.of_LoadImage(as_imagename, aul_index)
lstr_NID.szTip    = aw_window.title

// add icon to system tray
If Shell_NotifyIcon(NIM_ADD, lstr_NID) Then
   // make window invisible
   aw_window.Hide()
   Return True
Else
   Return False
End If

end function

public function boolean of_balloon_tip (window aw_window, string as_title, string as_info, unsignedlong aul_timeout, icon dwinfoflag);// create balloon tip in the system tray using a messagebox icon
// Note: to close a balloon tip, call with as_info an empty string

NOTIFYICONDATA lstr_NID

// populate structure
lstr_NID.cbSize      = NOTIFYICONDATA_SIZE
lstr_NID.hWnd        = Handle(aw_window)
lstr_NID.uID         = 1
lstr_NID.uTimeout    = aul_timeout
lstr_NID.uFlags      = NIF_INFO + NIF_SHOWTIP
lstr_NID.szInfoTitle = as_title
lstr_NID.szInfo      = as_info

Choose Case dwinfoflag
   Case StopSign!
      lstr_NID.dwInfoFlags = NIIF_ERROR
   Case Information!
      lstr_NID.dwInfoFlags = NIIF_INFO
   Case None!
      lstr_NID.dwInfoFlags = NIIF_NONE
   Case Exclamation!
      lstr_NID.dwInfoFlags = NIIF_WARNING
   Case Else
      lstr_NID.dwInfoFlags = NIIF_NONE
      lstr_NID.hIcon = Send(lstr_NID.hWnd, WM_GETICON, ICON_SMALL, 0)
End Choose

// create balloon tip
Return Shell_NotifyIcon(NIM_MODIFY, lstr_NID)

end function

on n_icontray.create
call super::create
TriggerEvent( this, "constructor" )
end on

on n_icontray.destroy
TriggerEvent( this, "destructor" )
call super::destroy
end on

event destructor;Integer li_cnt, li_max

// destroy icon handles created by ExtractIcon function
li_max = UpperBound(iptr_iconhandles)
FOR li_cnt = 1 TO li_max
   DestroyIcon(iptr_iconhandles[li_cnt])
NEXT

end event

event constructor;// determine version of NOTIFYICONDATA to use

Environment le_env

GetEnvironment(le_env)

NOTIFYICON_VERSION = this.of_DllVersion()

CHOOSE CASE NOTIFYICON_VERSION
   CASE 4
      NOTIFYICONDATA_SIZE = NOTIFYICONDATA_V4_SIZE
   CASE 3
      NOTIFYICONDATA_SIZE = NOTIFYICONDATA_V3_SIZE
   CASE 2
      NOTIFYICONDATA_SIZE = NOTIFYICONDATA_V2_SIZE
   CASE ELSE
      NOTIFYICONDATA_SIZE = NOTIFYICONDATA_V1_SIZE
END CHOOSE

// Add Unicode string lengths
NOTIFYICONDATA_SIZE = NOTIFYICONDATA_SIZE + 448

// Add Longptr size
If le_env.ProcessBitness = 64 Then
   NOTIFYICONDATA_SIZE = NOTIFYICONDATA_SIZE + 12
End If

end event