A customer had a question and sent some code:
oHandler = NEWOBJECT("StatusBarText")
_VFP.StatusBar = "AAAA" && triggers handler
SET MESSAGE TO "1111" && does not trigger handler
*navigate menus: does not trigger handler
DEFINE CLASS StatusBarText AS Session
This code demonstrates 3 ways to change the status bar text, but only one fires the hooked event.
The status bar text can change in various ways, which means there are various code paths internal to VFP that are followed. When changing the status bar text directly via direct assignment to _VFP.Statusbar, the normal VFP code (the object manager) that changes an object’s property gets invoked, which knows to check for and execute any BindEvent code.
When the user activates a menu, the WM_ENTERIDLE Notification is sent to VFP’s Window procedure with WPARAM = MSGF_MENU, which tells VFP to draw the menu message on the status bar.
When the user executes SET MESSAGE TO, the internal VFP object manager is completely bypassed to change the status bar text.
The BINDEVENT feature allows the user to bind events to when an object property or method is invoked or changed. When I implemented the feature, I modified the internal VFP object manager to check for user bound events. I paid no attention to the SET MESSAGE TO and the WM_ENTERIDLE code, which had been in existence for several versions.
I suppose one could argue that this is a bug, but the documentation says:
to bind events, properties, or methods from native Visual FoxPro objects to other Visual FoxPro objects.
There is a simple workaround: use Bindevents to bind to the WM_ENTERIDLE message and change SET MESSAGE TO cNewMessage to _VFP.StatusBar=cNewMessage
#define GWL_WNDPROC (-4)
#define WM_ENTERIDLE 0x0121
#define MSGF_DIALOGBOX 0
#define MSGF_MESSAGEBOX 1
#define MSGF_MENU 2
#define MSGF_SCROLLBAR 5
SET MESSAGE TO TRANSFORM(SECONDS()) && does not trigger handler
DECLARE integer GetWindowLong IN WIN32API ;
integer hWnd, ;
DECLARE integer CallWindowProc IN WIN32API ;
integer lpPrevWndFunc, ;
integer hWnd,integer Msg,;
PROCEDURE HandleMsg(hWnd as Integer, msg as Integer, wParam as Integer, lParam as Integer)
* ?PROGRAM(),msg,TRANSFORM(wParam,"@0x"),TRANSFORM(lParam,"@0x")," "
CASE msg =WM_ENTERIDLE
IF wParam = MSGF_MENU
*call default processing to set menu message
See also How to hook command window keystrokes.
Why doesn't drag/drop work with BindEvents?
Is this a bug in BindEvents?