Table of Contents
Hyperlinks in text boxes
by Richard Russell, January 2007
The code in this article is not applicable to Windows 9x, Windows Me or Windows NT4.
On occasion you may want to incorporate clickable hyperlinks in some text displayed in a dialogue box or elsewhere. For example you may want to incorporate a web or email address in a page of help text. One way of doing that would be to write the text in HTML and display it using your browser (for example in an ATL container control) but a simpler method is described in this article. This method also gives you control over the action to be taken when the link is clicked.
You must initially prepare the text to be displayed, where the hyperlinks are delimited using <A> and </A> tags as in the following example:
linktext$ = "For details of the full version of BBC BASIC for Windows email "+ \ \ "<A>info@rtrussell.co.uk</A> or visit <A>http://www.bbcbasic.co.uk/</A>"
Here two hyperlinks are included in the text string, but there can be as many as you like. You can also incorporate line breaks using the usual CRLF sequence (“CHR$13+CHR$10”).
You can display the text either in a dialogue box or on your main output window. The method used differs slightly between these options, and will be described separately.
Dialogue box
Firstly some initialisation:
INSTALL @lib$+"WINLIB2B" DIM _NMHDR{hwndFrom%, idFrom%, code%} DIM _LITEM{mask%, iLink%, state%, stateMask%, szID&(95), szUrl&(4165)} SYS "LoadLibrary", "SHELL32.DLL" TO shell32% SYS "GetProcAddress", shell32%, 258 TO LinkWindow_RegisterClass% SYS LinkWindow_RegisterClass%
Note that in this application you must use WINLIB2B (rather than WINLIB2 or WINLIB2A) so that the WM_NOTIFY messages are forwarded and can be intercepted using ON SYS.
The next step is to create the dialogue box. In this example it contains only the link window, but you can of course incorporate any of the normal dialogue box controls:
lwid% = 101 dlg% = FN_newdialog("Hyperlink control", 200, 20, 150, 140, 8, 1000) WS_CHILD = &40000000 WS_VISIBLE = &10000000 PROC_dlgctrl(dlg%, "", lwid%, 20, 20, 96, 40, WS_CHILD + WS_VISIBLE, "Link Window")
Note that the link window has been allocated the ID number 101. Refer to the documentation for PROC_dlgitem for the meaning of the other parameters.
Now you can display the dialogue box and load the required link text:
PROC_showdialog(dlg%) SYS "SetDlgItemText", !dlg%, lwid%, linktext$
Note the use of the control's ID number lwid%.
Finally you need to be able to detect when one of the links is clicked, so that you can take the appropriate action. You do that in a similar way to responding to menu and button clicks, using ON SYS:
*SYS 1 WM_NOTIFY = &4E ON SYS PROCsys(@msg%, @wparam%, @lparam%) : RETURN
The PROCsys routine is listed at the end of the article.
Main output window
Firstly some initialisation:
INSTALL @lib$+"WINLIB5" DIM _NMHDR{hwndFrom%, idFrom%, code%} DIM _LITEM{mask%, iLink%, state%, stateMask%, szID&(95), szUrl&(4165)} SYS "LoadLibrary", "SHELL32.DLL" TO shell32% SYS "GetProcAddress", shell32%, 258 TO LinkWindow_RegisterClass% SYS LinkWindow_RegisterClass%
You can alternatively use the WINLIB5A library, in which case remember to pass the window handle @hwnd% as the first parameter of FNcreatewindow.
The link window is created, with the required text, as follows:
lwid% = 101 WS_BORDER = &800000 hlink% = FN_createwindow("Link Window", linktext$, 50, 100, 400, 80, \ \ lwid%, WS_BORDER, 0)
Refer to the documentation for FN_createwindow for the meaning of the parameters.
Finally you need to be able to detect when one of the links is clicked, so that you can take the appropriate action. You do that in a similar way to responding to menu and button clicks, using ON SYS:
*SYS 1 WM_NOTIFY = &4E ON SYS PROCsys(@msg%, @wparam%, @lparam%) : RETURN
The PROCsys routine is listed below.
PROCsys
The interrupt service routine listed below responds the WM_NOTIFY messages received from the link window when one of the hyperlinks is clicked:
DEF PROCsys(M%, W%, L%) CASE M% OF WHEN WM_NOTIFY: LOCAL nmlink{} DIM nmlink{hdr{}=_NMHDR{}, item{}=_LITEM{}} !(^nmlink{}+4) = L% IF nmlink.hdr.idFrom% = lwid% AND nmlink.hdr.code% = -2 THEN PRINT "Clicked link ";nmlink.item.iLink% ENDIF ENDCASE ENDPROC
If there is more than one hyperlink in the text you can determine which was clicked from the nmlink.item.iLink% value (0 corresponds to the first hyperlink, 1 to the second etc.). For the purposes of demonstration the value is printed to the screen; in a real application you will want to take a different action.
Note that the usual precautions related to interrupt service routines apply, and you may wish to set a global flag which is tested elsewhere rather than process the action within PROCsys.
If, as is likely, your program needs to respond to other ON SYS events, such as menu selections and button presses, you will need to extend the PROCsys routine by adding a WHEN clause to intercept the WM_COMMAND (&111) messages.