Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Trouble with GetWindowText

llynisa
Beginner
3,679 Views

I am attempting to read the text of a button in order to transfer it to another. The text of the first, IDCANCEL, is set in the resource file as Cancel without the inverted commas. When I use the command to read the text into the character*20 ButtonStr:

lBtnStr = GetWindowText(hButton, ButtonStr, 20) ! Get Button text.

The return value of lBtnStr is 19, rather than the expected 6.

The 7th to 20th characters of ButtonStr are not uniform blanks, do not contain any nulls = char(0) but do contain the occasional alphanumeric character.

When subsequently written into another button, it is treated as being of length 19, not 6, which ruins the centering.

Other WinAPIs are no better or worse, with GetWindowTextLength returning 280 and GetDlgItemText 19.

Any ideas please?

Llynisa

0 Kudos
31 Replies
llynisa
Beginner
1,066 Views
Tony,

Thanks - alot to digest there. I will produce a stripped-down version of my program and post it here, also try some of the diagnostics you suggest.

Unfortunately I am just about to have my pacemaker changed at short notice (one of the delights of geriatricity), so there may be a delay. At least the new pacemaker will be internet-compatible.

Llynisa
0 Kudos
llynisa
Beginner
1,066 Views

On BS_OWNERDRAW style and XFLogm, the best answer that I can suggest is to look at Yugoslavs info at:http://www.xeffort.com/fortran/xflogm/xflogm.htm

I attach the files necessary to build a simple version of my program whilst I look into debugging it.

Create an empty Fortran Windows Application project and add the files BtnClrA.f90, XFLogm.f90, BtnClrA.rc, BtnClrA.h & BtnClrA.fd. If you are using CVF, they should build an .exe without trouble, but for IVF, make changes appropriately. The .exe that I have built is attached as BtnClrA.exe and its displayed dialogue box is as in BtnClrA.jpg.

The method of drawing and colouring the button is simple, with the edges of the button being uncoloured. Also the coloured centre does not move one pixel sideways and down when clicked upon. If anyone can advise me how to incorporate these refinements, it would be greatly appreciated.

Llynisa

0 Kudos
IanH
Honored Contributor II
1,066 Views
The control's text is being padded with blanks. You get 19 back from the GetWindowText call because your receiving buffer is only 20 bytes long and the last byte is used for the terminating NULL.

At the instant of dialog creation the control is created with the "right" text, but during WM_INITDLG processing by XFLOGM the control's text is explicitly changed to include the trailing blanks. You can see that in the following message trace:



The offending call is on line 1848 of the XFLOGM.f90 that you attached. The text of the control has been parsed out of the resource template by previous parts of the library into a fixed length character variable (the only sort available prior to F2003 - now that would probably be better off being an deferred length allocatable component, i.e. CHARACTER(:), ALLOCATABLE :: xxx, alternatively the trailing null sentinel could have been left in the component's value or the signficant length tracked separately). You could also just TRIM the text argument of the WM_SETTEXT message, or just TRIM the results of your GetWindowText call in your code - it is probably fair enough to assume that trailing blanks will never be significant in a window's caption.
0 Kudos
anthonyrichards
New Contributor III
1,066 Views
...and a probelm that turns up with the posted program is that the frequently-called function PadStrFor in XFLOGM.F90 can overrun the buffer if the 'expected' trailing null character char(0) is not present when the function looks for it in the supplied string in order to pad it with blanks out to the end of the string. You need to change the function code to stop searching when you have reached the end of the supplied string.

The present code fails in that case by assuming that the second part of the test

i .le. len(str0.and. str(i:i) .ne. char(0)

will not be executed if i exceeds len(str), which it will do because of the i=i+1.
(This has been discussed in a recent thread). The attached code is better as it exits the WHILE loop as soon as i exceeds len(str) and prevents the code trying to access str(i:i) when i exceeds the strings length.

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! PadStrFor
!!
!! Pads out a null terminated string (C string to F90 string)
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

recursive subroutine PadStrFor( str )
character*(*), intent(inout) :: str
integer i, lstr
! scan up to the terminating null
i = 1
lstr=len(str)
do while( i .le. lstr.and. str(i:i) .ne. char(0) )
i = i + 1
if(i.gt.lstr) exit
end do
! pad the rest with blanks
do while( i .le. lstr )
str(i:i) = ' '
i = i + 1
end do
end subroutine PadStrFor

P.S.
GetWindowText help says "If the function succeeds, the return value is the length, in characters, of the copied string, not including the terminating null character." (my emphasis). So any terminating null character is ignored by this function during the copy to the user-supplied buffer. Clearly, if there is no terminating null character, the function may copy some rubbish to the user-supplied buffer, up to the end of the buffer holding the window's text.

0 Kudos
IanH
Honored Contributor II
1,066 Views
GetWindowText help says "If the function succeeds, the return value is the length, in characters, of the copied string, not including the terminating null character." (my emphasis). So any terminating null character is ignored by this function during the copy to the user-supplied buffer. Clearly, if there is no terminating null character, the function may copy some rubbish to the user-supplied buffer, up to the end of the buffer holding the window's text.

I might not have correctly followed what you are saying here, but while the returned length doesn't include the terminating null, the api (or the target window proc handling the WM_GETTEXT message) will always append a terminating null (unless the target window proc is doing something daft, or the programmer has passed in a zero length buffer). Otherwise you'd have C programs exploding all over the shop.

0 Kudos
llynisa
Beginner
1,066 Views

Thanks to all of you for getting me started - I dug back to where the text was read and set. It appears to me that the offendingplacein XFlogm is line 5267:

ctrlHeader%textName(iSt:iSt)=" "

iSt =7, so it sets not a terminating null but a space.

changing the line to:

ctrlHeader%textName(iSt:iSt)=char(0) !" " BearofLittleBrain amendment.

solves the problem and gives thecorrect text display in the button.

I've only tested it in the one example program that I posted, but it feels as if it is the correct fix.

BearofLittleBrain

0 Kudos
anthonyrichards
New Contributor III
1,066 Views
I attach a modified version of your version of BackColor which correctly draws both pushed and unpushed buttons in your chosen colours. I found that the program would crash on double-clicking the Apply button and traced this to a vagary of the XFLOGM code, which I have explained in an included README text file.
I substituted a routine called DrawButton for your button-colouring routine to draw the correct frame using the DrawEdge function and to draw the button text using function DrawText. This is done in response to a WM_DRAWITEM message sent by both owner-draw style buttons, Apply and Exit.
If you use DrawFrameControl, it always draws a frame with the default background, it appears, so I had to drop using that.

The colouring of the button backgrounds is done by first intercepting the WM_CTLCOLORBTN mesage for the Apply and Exit buttons and returning a handle to the required background brush in each case.

I think the only fortran file I have not modified is CVFCOLOURS. Button colour choices are made in the BackColorSub callback routine on initialisation of the dialog, and colours and control window handles etc are saved in the BackColorGlobals module for use wherever they are required.

I have added code to add a terminating char(0) to each text string before drawing it on a button.

I include screen dumps of the dialog with and without a clicked Apply button. A message box is put up when the Apply button is clicked.
0 Kudos
llynisa
Beginner
1,066 Views
Tony,

Congratulations - that looks just the ticket! A minor query - should the button centre not move 1 pixel right & down rather than left & up when pushed?

Yes, I recognised thatDrawFrameControlblocked out the centre, so yours is a better approach. I will take a longer look at it later and see what set of mods to XFLOGM are needed following yourlast proposal on double-clicking, your previous one on PadStrFor and mine on adding a terminal null.

Llynisa
0 Kudos
anthonyrichards
New Contributor III
1,066 Views
Forget about adding a terminal null to the text drawn to the control. It shows up wrong. I do not use it as a result.

You can play with the edge style used in the DrawEdge function to suit using the one or more of the various options, of which BF_RECT is just one. You can draw a black frame Rectangle around it to show it has focus too.
e.g.
if(BtnState.and.ODS_SELECTED) then
iret=DrawEdge(hdccontrol,RC,EDGE_SUNKEN,BF_TOPRIGHT)
!Draw frame rectangle if button selected
iret=FrameRect(hdccontrol, RC, GetStockObject(BLACK_BRUSH))

or

IF(GetFocus().eq.hbutton) iret=FrameRect(hdccontrol, RC, GetStockObject(BLACK_BRUSH))

0 Kudos
bearoflittlebrain_ol
1,066 Views
The terminal null problem seems to be completely sorted by modifying the last routine in XFLogm, FDlgParseResControl.

ctrlHeader%textName(iSt:iSt)=" "

should be changed to:

ctrlHeader%textName(iSt:iSt)=char(0) !" " AJC modification.

Similarly

ctrlHeader%className(iSt:iSt)=" "

should be changed to

ctrlHeader%className(iSt:iSt)=char(0) !" " AJC modification.

Then one can get rid of LenTrimAll, which is only used in desperation.
0 Kudos
anthonyrichards
New Contributor III
1,066 Views
Good! I will give it a go ASAP.
0 Kudos
Reply