Yes, I know this behavior is documented in the help but I can't understand why Richard decided to put this in the WINLIB2B library or actually why he didn't just update WINLIB2.
As far as I can see from other applications (including BB4W IDE!) pressing escape or clicking the dialog box close button closes the dialog box.
Obviously the advantage to use WINLIB2B over WINLIB2 is that it forwards also WM_HELP and WM_NOTIFY messages. And yes, that is what I want as I need a WM_NOTIFY when an item in a ListView selected.
Still I fail to see why Richard didn't just update the WINLIB2 library because the programmer has control to allow/disallow this by *SYS1.
Bottom line is that I want/need to receive WM_NOTIFY but also to have close buttons behave in a common way, i.e. as in WINLIB2.
Do I need to modify WINLIB2B library assembly code (and how) or is there is simpler solution?
You will get an interrupt message of WM_COMMAND (@msg%=273) with a control ID of ID_CANCEL (@wparam%=2) so you will look for this in your interrupt handler and issue a QUIT or whatever else you wish to do with that input.
That is much simpler than messing with the library and customizing it.
Hope this helps.
Thanks for the fast reply!
Actually I discovered today that at least WM_COMMAND with ID_CANCEL is send so I thought I was saved and that I could simply add this in my interrupt handler PROCedure, which is.....
Code: Select all
DEF PROCappSys(msg%, wpa%, lpa%) LOCAL nc%, id% nc%=wpa%>>16 : id%=wpa% AND &FFFF CASE msg% OF WHEN WM_COMMAND REM Dialog buttons... CASE id% OF WHEN 190, 199 PROCappAddCol(id%) WHEN 290, 299 PROCappCDSet(id%) WHEN 390, 399 PROCappOperations(id%) ...................... WHEN 9990 PROCdebug(id%, "") ENDCASE IF id%>469 IF id%<480 PROCappCDWidths(id%) IF id%>=10000 PROCappCellDetails(20, id%) IF id%=710 IF nc%=EN_CHANGE PROCappSearchAlbum(10) IF id%=720 IF nc%=LBN_SELCHANGE PROCappSearchAlbum(30) WHEN WM_NOTIFY IF id%=400 IF nc%=LVN_ITEMCHANGED PROCappCDWidths(10) ENDCASE ENDPROC
However when receiving ID_CANCEL (@wparam%=2), the program doesn't know which dedicated PROC to call, i.e. for dialog box to issue PROC_closedialog().
Hope the above makes sense.
You could always have asked him! The reason for the change in the behaviour of the Close button and the Escape key in WINLIB2B is simply because the way they behave in WINLIB2 is wrong! It is never sensible for a dialogue box unconditionally to close when Close or Escape is pressed: the programmer should always have the opportunity to suppress that action if it is not appropriate in the circumstances (like ON CLOSE in the main output window). Richard wasn't able to fix this in WINLIB2 because it would have introduced an incompatibility, but WINLIB2B gave him the opportunity to do it correctly.
The proper way for Close and Escape to work, and how they work in WINLIB2B, is for them to generate a WM_COMMAND message with an ID of 2 (Cancel); that can be intercepted in the normal way and, assuming you want the dialogue box to be closed as a result, you can call PROC_closedialog() to achieve that. Indeed if you look at the code of DLGDEMO.BBC you'll see that this is exactly what happens (even though WINLIB2 is normally used, you can change it to WINLIB2B and it will behave in exactly the same way).
The situation you describe there is extremely unusual, because it implies that there are two or more 'modeless' dialogue boxes open at the same time. In Windows dialogue boxes are almost always modal (in which case there is no ambiguity in respect of which is being closed); modeless dialogue boxes (such as the Find/Replace dialogue) are uncommon and having two or more open at the same time is a situation Richard has never encountered.
So if you really do have two modeless dialogue boxes Richard would be concerned that your user interface is exceptionally non-standard. If you can make the dialogue boxes modal, and hence more conventional, there cannot be any doubt about which is being closed. As a last resort, if you are convinced modeless dialogue boxes are appropriate, you can still distinguish which is being closed because the lParam value passed in the WM_COMMAND message will contain the handle of the Cancel button in the relevant box (even if Close or Escape was pressed).
I agree that my handling of modal vs modeless boxes is an ongoing issue. Most of them can or rather should be modal.
Because of a menu-choice I call a PROC that opens the correct dialog box, like:
Code: Select all
CASE msg% OF WHEN WM_COMMAND REM Menu handling... CASE id% OF ............. WHEN 25 PROCappSearchAlbum(0) .............
Code: Select all
IF id%=710 IF nc%=EN_CHANGE PROCappSearchAlbum(10) IF id%=720 IF nc%=LBN_SELCHANGE PROCappSearchAlbum(30)
Kind of defies my approach of keeping all functionality from the same dialog box (each control on it) in a dedicated PROC.
Will give it more thought I guess.
Windows is designed in such a way that controls need not have unique IDs, for example the 'built in' dialogue boxes commonly reuse the same ID. So although that's something you can do when you have control of the IDs, it's not a general solution (and as you've noted the IDs for OK and Cancel/Close are mandated).
You could still do that, but the 'dispatch' mechanism that determines which PROC is called would have to take account of something which identifies the dialogue box. You could for example dispatch on the *handle* of the originating control rather than its *ID* (i.e. use lParam rather than wParam) which is guaranteed to be unique. As I said, if you press Escape or Close it will appear to have originated from the Cancel button according to the handle value.
Code: Select all
REM This does not work. INSTALL @lib$+"WINLIB2B" : dlg%=FN_newdialog("First",50,50,100,100,8,200) PROC_showdialog(dlg%) dlg1%=FN_newdialog("Second",250,50,100,100,8,200) PROC_showdialog(dlg1%) dlg2%=FN_newdialog("Third",450,50,100,100,8,200) PROC_showdialog(dlg2%) : DIM Q%(2) ON SYS Q%()=@msg%, @wparam% AND &FFFF, @lparam% : RETURN REM ========================== MAIN LOOP ============================= REPEAT IF Q%(1) = 2 THEN CASE TRUE OF WHEN Q%(2)=!dlg%: PROC_closedialog(dlg%) WHEN Q%(2)=!dlg1%: PROC_closedialog(dlg1%) WHEN Q%(2)=!dlg2%: PROC_closedialog(dlg2%) ENDCASE PRINT Q%(0), Q%(1), Q%(2) ENDIF Q%()=0 WAIT 10 UNTIL FALSE END
Please thank Richard for his reply. He always provides good information.
So I was thinking of getting the dialog handle when there is a ID_CANCEL and then give all dialog-PROCs a change to match the dlg and do their business.
Was about to test how to obtain the handle today but.... Zaphod beat me to it and saves me a lot of work.
Zaphod: Thanks. And you say also "GetActiveWindow" doesn't work, right?
Your elegant piece of code shows my problem exactly! Even IF it would work, I need a WHEN for every possible value of dlg%. It also implies that all handles should be in global variables. They aren't. All the dialog-PROCs have a PRIVATE dlg%.
Then again, giving each PROC a chance to match is far more elegant I would say. But....... handle can't be found!
Only 'solution' I can think of is add code to all PROCs to save dlg% in a global OpenDlg% to indicate which box is open and then upon receiving ID_CANCEL do a PROC_closedialog(OpenDlg%).