Discussion:
GetWindowText() issue
(too old to reply)
Leslie Milburn
2007-09-24 15:57:51 UTC
Permalink
Hi all,

Standard ANSI C Win32 application - no Unicode anywhere.
I want to retrieve the first 7 bytes of the current value of a
Combobox field on a window (all owned).
All values in the Combo Dropdown list are approx 20 bytes
in length.

So the code essentially is

TCHAR Buffer[8];

rc = GetWindowText(hWndCombo, Buffer, sizeof(Buffer));

Under Win9x:
rc = 8 (although it should be 7 according to the documentation as it should
not include the NULL character).

Under Windows XP SP2
rc = 16 and more importantly it is over-running the buffer.

I have tried calling GetWindowTextA() and I have also tried SendMessage(...,
WM_GETTEXT...) but under Windows XP it is ignoring the buffer size parameter
altogether.

I have confirmed that sizeof(Buffer) is correct, and I have even confirmed
sizeof(TCHAR) is 1 byte.

Can anyone reproduce this problem as it is frustrating the hell out of me.
Leslie.
Kellie Fitton
2007-09-24 17:48:51 UTC
Permalink
Post by Leslie Milburn
Hi all,
Standard ANSI C Win32 application - no Unicode anywhere.
I want to retrieve the first 7 bytes of the current value of a
Combobox field on a window (all owned).
All values in the Combo Dropdown list are approx 20 bytes
in length.
So the code essentially is
TCHAR Buffer[8];
rc = GetWindowText(hWndCombo, Buffer, sizeof(Buffer));
rc = 8 (although it should be 7 according to the documentation as it should
not include the NULL character).
Under Windows XP SP2
rc = 16 and more importantly it is over-running the buffer.
I have tried calling GetWindowTextA() and I have also tried SendMessage(...,
WM_GETTEXT...) but under Windows XP it is ignoring the buffer size parameter
altogether.
I have confirmed that sizeof(Buffer) is correct, and I have even confirmed
sizeof(TCHAR) is 1 byte.
Can anyone reproduce this problem as it is frustrating the hell out of me.
Leslie.
Hi,

How about using the following function to get the length
of the text first:

GetWindowTextLength()
Also,
IsTextUnicode()

http://msdn2.microsoft.com/en-us/library/ms633521.aspx

http://msdn2.microsoft.com/en-us/library/ms776445.aspx

Kellie.
Leslie Milburn
2007-09-25 00:06:16 UTC
Permalink
Post by Kellie Fitton
GetWindowTextLength()
Also,
IsTextUnicode()
http://msdn2.microsoft.com/en-us/library/ms633521.aspx
http://msdn2.microsoft.com/en-us/library/ms776445.aspx
Kellie.
Hi Kellie,

Yep already thought about that. The GetWindowTextLength is returning the
length of the currently selected item in the Combobox and so it returns 22
which is correct. Remember that I only wanted the first 7 bytes and so I set
the buffer to 8 to allow for 7 bytes plus the NULL, always has worked on
Win9x.

Anyway, for the record I have found the problem, and oh boy I cannot believe
it. I would be grateful if someone else can confirm what I am seeing here.
Here is the minimum code to repeat the problem..... (remember no UNICODE)

{
char Buffer[10];

Buffer[0] = '0';
Buffer[1] = '1';
Buffer[2] = '2';
Buffer[3] = '3';
Buffer[4] = '4';
Buffer[5] = '5';
Buffer[6] = '6';
Buffer[7] = '7';
Buffer[8] = '8';
Buffer[9] = '9';

Index = SendMessage(hWndCombo, CB_ADDSTRING, 0, "ABCDEFGHIJKLMNOP");
SendMessage(hWndCombo, CB_SETCURSEL, Index, 0);

GetWindowText(hWndCombo, Buffer, 7);
}

Running this on Win9x: Buffer contains "ABCDEF" as expected (6 chars plus
the NULL).
Running this on WinXP SP2: Buffer contains "ABCDEFG789" (not expected by me,
7 chars total).

This means no terminating NULL is being stored in the buffer and so we have
a buffer overrun.

Can anyone else confirm this behaviour ?
Thanks
Leslie.
Joe Butler
2007-09-25 01:20:18 UTC
Permalink
Well, the docs in the feb 2003 sdk say this:

"Pointer to the buffer that will receive the text. If the string is as long
or longer than the buffer, the string is truncated and terminated with a
NULL character. "

Guess it means, if the text fits with room to spare, no termination will
occur, but you are able to get the text lenght beforehand. A mistake I
would have made too. And with the GetWindowTextLength() call, I guess one
is expected to dynamically allocate the buffer first - that would be safest
option if you check all your return values, etc.
Post by Leslie Milburn
Post by Kellie Fitton
GetWindowTextLength()
Also,
IsTextUnicode()
http://msdn2.microsoft.com/en-us/library/ms633521.aspx
http://msdn2.microsoft.com/en-us/library/ms776445.aspx
Kellie.
Hi Kellie,
Yep already thought about that. The GetWindowTextLength is returning the
length of the currently selected item in the Combobox and so it returns 22
which is correct. Remember that I only wanted the first 7 bytes and so I
set the buffer to 8 to allow for 7 bytes plus the NULL, always has worked
on Win9x.
Anyway, for the record I have found the problem, and oh boy I cannot
believe it. I would be grateful if someone else can confirm what I am
seeing here. Here is the minimum code to repeat the problem..... (remember
no UNICODE)
{
char Buffer[10];
Buffer[0] = '0';
Buffer[1] = '1';
Buffer[2] = '2';
Buffer[3] = '3';
Buffer[4] = '4';
Buffer[5] = '5';
Buffer[6] = '6';
Buffer[7] = '7';
Buffer[8] = '8';
Buffer[9] = '9';
Index = SendMessage(hWndCombo, CB_ADDSTRING, 0, "ABCDEFGHIJKLMNOP");
SendMessage(hWndCombo, CB_SETCURSEL, Index, 0);
GetWindowText(hWndCombo, Buffer, 7);
}
Running this on Win9x: Buffer contains "ABCDEF" as expected (6 chars plus
the NULL).
Running this on WinXP SP2: Buffer contains "ABCDEFG789" (not expected by
me, 7 chars total).
This means no terminating NULL is being stored in the buffer and so we
have a buffer overrun.
Can anyone else confirm this behaviour ?
Thanks
Leslie.
Leslie Milburn
2007-09-25 01:40:41 UTC
Permalink
Hi Joe,

Thanks for the response.

I would agree with you but look at my example. The buffer is 10 bytes and I
am only asking for 7. There is room for the terminator but it just does not
happen - it is returning 7 characters regardless. So what do I have to do to
get the termination byte to occur ? The more I think about it the weirder it
gets.

Leslie.
Post by Joe Butler
"Pointer to the buffer that will receive the text. If the string is as
long or longer than the buffer, the string is truncated and terminated
with a NULL character. "
Guess it means, if the text fits with room to spare, no termination will
occur, but you are able to get the text lenght beforehand. A mistake I
would have made too. And with the GetWindowTextLength() call, I guess one
is expected to dynamically allocate the buffer first - that would be
safest option if you check all your return values, etc.
Post by Leslie Milburn
Post by Kellie Fitton
GetWindowTextLength()
Also,
IsTextUnicode()
http://msdn2.microsoft.com/en-us/library/ms633521.aspx
http://msdn2.microsoft.com/en-us/library/ms776445.aspx
Kellie.
Hi Kellie,
Yep already thought about that. The GetWindowTextLength is returning the
length of the currently selected item in the Combobox and so it returns
22 which is correct. Remember that I only wanted the first 7 bytes and so
I set the buffer to 8 to allow for 7 bytes plus the NULL, always has
worked on Win9x.
Anyway, for the record I have found the problem, and oh boy I cannot
believe it. I would be grateful if someone else can confirm what I am
seeing here. Here is the minimum code to repeat the problem.....
(remember no UNICODE)
{
char Buffer[10];
Buffer[0] = '0';
Buffer[1] = '1';
Buffer[2] = '2';
Buffer[3] = '3';
Buffer[4] = '4';
Buffer[5] = '5';
Buffer[6] = '6';
Buffer[7] = '7';
Buffer[8] = '8';
Buffer[9] = '9';
Index = SendMessage(hWndCombo, CB_ADDSTRING, 0, "ABCDEFGHIJKLMNOP");
SendMessage(hWndCombo, CB_SETCURSEL, Index, 0);
GetWindowText(hWndCombo, Buffer, 7);
}
Running this on Win9x: Buffer contains "ABCDEF" as expected (6 chars plus
the NULL).
Running this on WinXP SP2: Buffer contains "ABCDEFG789" (not expected by
me, 7 chars total).
This means no terminating NULL is being stored in the buffer and so we
have a buffer overrun.
Can anyone else confirm this behaviour ?
Thanks
Leslie.
Joe Butler
2007-09-25 05:10:02 UTC
Permalink
no way. the GetWindowText doesn't know how large the actual buffer is, it
only knows the length you give it. Tell it that a 2 char array is 256 bytes
and it'll happily fill it up if necesary.

To get the terminator:

// zero fill the destination buffer and make it 1 larger than we need.
char buf[8]= {0};

// get teh 7 chars (up to 7 chars)
getwindowtext(blah blah, 7);


that way, start off with a zero-filled array, so when getwindowtext puts up
to 7 chars in there, the next char is guarenteed to be a zero.
Post by Leslie Milburn
Hi Joe,
Thanks for the response.
I would agree with you but look at my example. The buffer is 10 bytes and
I am only asking for 7. There is room for the terminator but it just does
not happen - it is returning 7 characters regardless. So what do I have to
do to get the termination byte to occur ? The more I think about it the
weirder it gets.
Leslie.
Post by Joe Butler
"Pointer to the buffer that will receive the text. If the string is as
long or longer than the buffer, the string is truncated and terminated
with a NULL character. "
Guess it means, if the text fits with room to spare, no termination will
occur, but you are able to get the text lenght beforehand. A mistake I
would have made too. And with the GetWindowTextLength() call, I guess
one is expected to dynamically allocate the buffer first - that would be
safest option if you check all your return values, etc.
Post by Leslie Milburn
Post by Kellie Fitton
GetWindowTextLength()
Also,
IsTextUnicode()
http://msdn2.microsoft.com/en-us/library/ms633521.aspx
http://msdn2.microsoft.com/en-us/library/ms776445.aspx
Kellie.
Hi Kellie,
Yep already thought about that. The GetWindowTextLength is returning the
length of the currently selected item in the Combobox and so it returns
22 which is correct. Remember that I only wanted the first 7 bytes and
so I set the buffer to 8 to allow for 7 bytes plus the NULL, always has
worked on Win9x.
Anyway, for the record I have found the problem, and oh boy I cannot
believe it. I would be grateful if someone else can confirm what I am
seeing here. Here is the minimum code to repeat the problem.....
(remember no UNICODE)
{
char Buffer[10];
Buffer[0] = '0';
Buffer[1] = '1';
Buffer[2] = '2';
Buffer[3] = '3';
Buffer[4] = '4';
Buffer[5] = '5';
Buffer[6] = '6';
Buffer[7] = '7';
Buffer[8] = '8';
Buffer[9] = '9';
Index = SendMessage(hWndCombo, CB_ADDSTRING, 0, "ABCDEFGHIJKLMNOP");
SendMessage(hWndCombo, CB_SETCURSEL, Index, 0);
GetWindowText(hWndCombo, Buffer, 7);
}
Running this on Win9x: Buffer contains "ABCDEF" as expected (6 chars
plus the NULL).
Running this on WinXP SP2: Buffer contains "ABCDEFG789" (not expected by
me, 7 chars total).
This means no terminating NULL is being stored in the buffer and so we
have a buffer overrun.
Can anyone else confirm this behaviour ?
Thanks
Leslie.
Christian Kaiser
2007-09-25 06:19:25 UTC
Permalink
Post by Joe Butler
char buf[8]= {0};
// get teh 7 chars (up to 7 chars)
getwindowtext(blah blah, 7);
This would return 7 chars in (themed?) XP and 6 bytes in Win9x.

Christian
Leslie Milburn
2007-09-25 11:43:28 UTC
Permalink
Hi Joe,

Yes you are correct and thats what I am doing. If you look at my example I
declare char Buffer[10] and call GetWindowText(hWndCombo, Buffer, 7) - so
there is either 2 or 3 bytes spare for the terminator - the call simply does
not add the terminator - Read my other post off the main thread to find out
why.

Leslie.
Post by Joe Butler
no way. the GetWindowText doesn't know how large the actual buffer is, it
only knows the length you give it. Tell it that a 2 char array is 256
bytes and it'll happily fill it up if necesary.
// zero fill the destination buffer and make it 1 larger than we need.
char buf[8]= {0};
// get teh 7 chars (up to 7 chars)
getwindowtext(blah blah, 7);
that way, start off with a zero-filled array, so when getwindowtext puts
up to 7 chars in there, the next char is guarenteed to be a zero.
Post by Leslie Milburn
Hi Joe,
Thanks for the response.
I would agree with you but look at my example. The buffer is 10 bytes and
I am only asking for 7. There is room for the terminator but it just does
not happen - it is returning 7 characters regardless. So what do I have
to do to get the termination byte to occur ? The more I think about it
the weirder it gets.
Leslie.
Post by Joe Butler
"Pointer to the buffer that will receive the text. If the string is as
long or longer than the buffer, the string is truncated and terminated
with a NULL character. "
Guess it means, if the text fits with room to spare, no termination will
occur, but you are able to get the text lenght beforehand. A mistake I
would have made too. And with the GetWindowTextLength() call, I guess
one is expected to dynamically allocate the buffer first - that would be
safest option if you check all your return values, etc.
Post by Leslie Milburn
Post by Kellie Fitton
GetWindowTextLength()
Also,
IsTextUnicode()
http://msdn2.microsoft.com/en-us/library/ms633521.aspx
http://msdn2.microsoft.com/en-us/library/ms776445.aspx
Kellie.
Hi Kellie,
Yep already thought about that. The GetWindowTextLength is returning
the length of the currently selected item in the Combobox and so it
returns 22 which is correct. Remember that I only wanted the first 7
bytes and so I set the buffer to 8 to allow for 7 bytes plus the NULL,
always has worked on Win9x.
Anyway, for the record I have found the problem, and oh boy I cannot
believe it. I would be grateful if someone else can confirm what I am
seeing here. Here is the minimum code to repeat the problem.....
(remember no UNICODE)
{
char Buffer[10];
Buffer[0] = '0';
Buffer[1] = '1';
Buffer[2] = '2';
Buffer[3] = '3';
Buffer[4] = '4';
Buffer[5] = '5';
Buffer[6] = '6';
Buffer[7] = '7';
Buffer[8] = '8';
Buffer[9] = '9';
Index = SendMessage(hWndCombo, CB_ADDSTRING, 0, "ABCDEFGHIJKLMNOP");
SendMessage(hWndCombo, CB_SETCURSEL, Index, 0);
GetWindowText(hWndCombo, Buffer, 7);
}
Running this on Win9x: Buffer contains "ABCDEF" as expected (6 chars
plus the NULL).
Running this on WinXP SP2: Buffer contains "ABCDEFG789" (not expected
by me, 7 chars total).
This means no terminating NULL is being stored in the buffer and so we
have a buffer overrun.
Can anyone else confirm this behaviour ?
Thanks
Leslie.
Christian Kaiser
2007-09-25 06:15:00 UTC
Permalink
How about

TCHAR Buffer[8];

Buffer[GetWindowText(hWndCombo, Buffer, sizeof(Buffer)/sizeof(TCHAR))] = 0;

This one call will make sure you get what you want. I assume the docs are
wrong in respect to the '\0' character if the string is longer than the
buffer. But keep in mind that themed XP has more bugs that unthemed XP,
especially in list- or comboboxes. You might want to test unthemend too ;-)

Christian
Post by Leslie Milburn
Post by Kellie Fitton
GetWindowTextLength()
Also,
IsTextUnicode()
http://msdn2.microsoft.com/en-us/library/ms633521.aspx
http://msdn2.microsoft.com/en-us/library/ms776445.aspx
Kellie.
Hi Kellie,
Yep already thought about that. The GetWindowTextLength is returning the
length of the currently selected item in the Combobox and so it returns 22
which is correct. Remember that I only wanted the first 7 bytes and so I set
the buffer to 8 to allow for 7 bytes plus the NULL, always has worked on
Win9x.
Anyway, for the record I have found the problem, and oh boy I cannot believe
it. I would be grateful if someone else can confirm what I am seeing here.
Here is the minimum code to repeat the problem..... (remember no UNICODE)
{
char Buffer[10];
Buffer[0] = '0';
Buffer[1] = '1';
Buffer[2] = '2';
Buffer[3] = '3';
Buffer[4] = '4';
Buffer[5] = '5';
Buffer[6] = '6';
Buffer[7] = '7';
Buffer[8] = '8';
Buffer[9] = '9';
Index = SendMessage(hWndCombo, CB_ADDSTRING, 0, "ABCDEFGHIJKLMNOP");
SendMessage(hWndCombo, CB_SETCURSEL, Index, 0);
GetWindowText(hWndCombo, Buffer, 7);
}
Running this on Win9x: Buffer contains "ABCDEF" as expected (6 chars plus
the NULL).
Running this on WinXP SP2: Buffer contains "ABCDEFG789" (not expected by me,
7 chars total).
This means no terminating NULL is being stored in the buffer and so we have
a buffer overrun.
Can anyone else confirm this behaviour ?
Thanks
Leslie.
Leslie Milburn
2007-09-25 11:44:54 UTC
Permalink
Post by Kellie Fitton
How about
TCHAR Buffer[8];
Buffer[GetWindowText(hWndCombo, Buffer, sizeof(Buffer)/sizeof(TCHAR))] = 0;
This one call will make sure you get what you want. I assume the docs are
wrong in respect to the '\0' character if the string is longer than the
buffer. But keep in mind that themed XP has more bugs that unthemed XP,
especially in list- or comboboxes. You might want to test unthemend too ;-)
Christian
Hi Christian,

I am not using themes at all. But given that sizeof(TCHAR) is 1 (I have
confirmed it), it makes no difference. However, I have made some progress on
the problem. I will reply to my original post so that it can easily be seen.

Leslie.
Christian Kaiser
2007-09-25 13:59:58 UTC
Permalink
My point is that my code always zero-terminates the buffer correctly.

Christian
Post by Leslie Milburn
Post by Kellie Fitton
How about
TCHAR Buffer[8];
Buffer[GetWindowText(hWndCombo, Buffer, sizeof(Buffer)/sizeof(TCHAR))] = 0;
This one call will make sure you get what you want. I assume the docs are
wrong in respect to the '\0' character if the string is longer than the
buffer. But keep in mind that themed XP has more bugs that unthemed XP,
especially in list- or comboboxes. You might want to test unthemend too ;-)
Christian
Hi Christian,
I am not using themes at all. But given that sizeof(TCHAR) is 1 (I have
confirmed it), it makes no difference. However, I have made some progress on
the problem. I will reply to my original post so that it can easily be seen.
Leslie.
Christian Kaiser
2007-09-25 14:02:17 UTC
Permalink
... assumed that there's not your Unicode Window issue ;-))))

Christian
Post by Christian Kaiser
My point is that my code always zero-terminates the buffer correctly.
Christian
Ivo Beltchev
2007-09-25 15:12:35 UTC
Permalink
Seems like there are 2 things wrong:
1) Sometimes the function returns 6 characters+NUL, sometimes 7 characters. In both cases though it doesn't write past the 7th char, so no buffer overflow here
2) The return value is wrong

If the above is true, it's probably a bug in Windows. Won't be the first one. So here's a possible workaround:
TCHAR Buffer[10];
GetWindowText(hWndCombo, Buffer, 8); // gets either 7 character+NUL, or 8 characters, ignore the return value
Buffer[7]=0; // force-terminate the string

Ivo
Post by Leslie Milburn
Post by Kellie Fitton
GetWindowTextLength()
Also,
IsTextUnicode()
http://msdn2.microsoft.com/en-us/library/ms633521.aspx
http://msdn2.microsoft.com/en-us/library/ms776445.aspx
Kellie.
Hi Kellie,
Yep already thought about that. The GetWindowTextLength is returning the
length of the currently selected item in the Combobox and so it returns 22
which is correct. Remember that I only wanted the first 7 bytes and so I set
the buffer to 8 to allow for 7 bytes plus the NULL, always has worked on
Win9x.
Anyway, for the record I have found the problem, and oh boy I cannot believe
it. I would be grateful if someone else can confirm what I am seeing here.
Here is the minimum code to repeat the problem..... (remember no UNICODE)
{
char Buffer[10];
Buffer[0] = '0';
Buffer[1] = '1';
Buffer[2] = '2';
Buffer[3] = '3';
Buffer[4] = '4';
Buffer[5] = '5';
Buffer[6] = '6';
Buffer[7] = '7';
Buffer[8] = '8';
Buffer[9] = '9';
Index = SendMessage(hWndCombo, CB_ADDSTRING, 0, "ABCDEFGHIJKLMNOP");
SendMessage(hWndCombo, CB_SETCURSEL, Index, 0);
GetWindowText(hWndCombo, Buffer, 7);
}
Running this on Win9x: Buffer contains "ABCDEF" as expected (6 chars plus
the NULL).
Running this on WinXP SP2: Buffer contains "ABCDEFG789" (not expected by me,
7 chars total).
This means no terminating NULL is being stored in the buffer and so we have
a buffer overrun.
Can anyone else confirm this behaviour ?
Thanks
Leslie.
r***@pen_fact.com
2007-09-25 20:00:42 UTC
Permalink
On Tue, 25 Sep 2007 10:06:16 +1000, "Leslie Milburn"
<***@NOSPAM.bigpond.com> wrote:

clip
Post by Leslie Milburn
Anyway, for the record I have found the problem, and oh boy I cannot believe
it. I would be grateful if someone else can confirm what I am seeing here.
Here is the minimum code to repeat the problem..... (remember no UNICODE)
{
char Buffer[10];
Buffer[0] = '0';
Buffer[1] = '1';
Buffer[2] = '2';
Buffer[3] = '3';
Buffer[4] = '4';
Buffer[5] = '5';
Buffer[6] = '6';
Buffer[7] = '7';
Buffer[8] = '8';
Buffer[9] = '9';
Index = SendMessage(hWndCombo, CB_ADDSTRING, 0, "ABCDEFGHIJKLMNOP");
SendMessage(hWndCombo, CB_SETCURSEL, Index, 0);
GetWindowText(hWndCombo, Buffer, 7);
}
Running this on Win9x: Buffer contains "ABCDEF" as expected (6 chars plus
the NULL).
Running this on WinXP SP2: Buffer contains "ABCDEFG789" (not expected by me,
7 chars total).
This means no terminating NULL is being stored in the buffer and so we have
a buffer overrun.
Can anyone else confirm this behaviour ?
Thanks
Leslie.
I've never seen such behavior, and I'm sure I've tested with XP SP2.
But I can't see any error in your code. The return code puzzles me.

This comment from my code might help:
For cautions/explanations about GetWindowText, see

"http://blogs.gotdotnet.com/raymondc/PermaLink.aspx/6da319c9-4f13-43aa-9bf3-210f2f2c8acd"
Also, see a 24 Aug 03 thread called "How is GetWindowText
working?" in
comp.os.ms-windows.programmer.win32

I _always_ allocate at least one extra character for the null
terminator; sort of lazy and paranoid.

For a work-around, I suggest making the buffer large enough to hold a
few extra characters, retrieving one less than the buffer size, and
then inserting a NULL at the 8th position.

-----------------------------------------
To reply to me, remove the underscores (_) from my email address (and please indicate which newsgroup and message).

Robert E. Zaret, eMVP
PenFact, Inc.
20 Park Plaza, Suite 478
Boston, MA 02116
www.penfact.com
Leslie Milburn
2007-09-25 13:02:46 UTC
Permalink
This post might be inappropriate. Click to display it.
Joe Butler
2007-09-25 14:27:27 UTC
Permalink
So, is the universal fix to use alloc (GetWindowTextLength() +
sizeof(TCHAR))
zero fill the buffer allocated.
get the window text.

?
Post by Leslie Milburn
Post by Leslie Milburn
Hi all,
Standard ANSI C Win32 application - no Unicode anywhere.
I want to retrieve the first 7 bytes of the current value of a
Combobox field on a window (all owned).
All values in the Combo Dropdown list are approx 20 bytes
in length.
So the code essentially is
TCHAR Buffer[8];
rc = GetWindowText(hWndCombo, Buffer, sizeof(Buffer));
rc = 8 (although it should be 7 according to the documentation as it
should not include the NULL character).
Under Windows XP SP2
rc = 16 and more importantly it is over-running the buffer.
I have tried calling GetWindowTextA() and I have also tried
SendMessage(..., WM_GETTEXT...) but under Windows XP it is ignoring the
buffer size parameter altogether.
I have confirmed that sizeof(Buffer) is correct, and I have even confirmed
sizeof(TCHAR) is 1 byte.
Can anyone reproduce this problem as it is frustrating the hell out of me.
Leslie.
Hi again,
Ok, heres an update on the problem and its a classic, you know you are alive
when you hit this sort of stuff.
I will write it out in full in case anyone else comes across the problem in
months/years to come.
Firstly the return code from GetWindowText() under Windows XP is *correct*,
it was *always* correct - because the Combobox is actually being seen by
Windows as a Unicode Window. I have confirmed it by calling
IsWindowUnicode().
So, passing 7 to the call was actually asking for 7 TCHARS which are double
byte characters and hence the return value of 14 is correct, its the number
of *BYTES* copied (not characters as documented) - and so hence the buffer
overflow.
How could I be so stupid ?? Well as you will see, I was not. I decided to
check the Parent Window Handle and all Child Controls with the
IsWindowUnicode() function. Guess what, all of them *except* the Combobox in
question are seen as ASCII windows. What the #$%& !!!!
Never before have I seen such a thing happen. So I have spent the last 24 or
so hours trawling through 1000's of lines of preprocessor output trying to
find any function calls with a W on the end, like CreateWindowExW() - but
NO, there are no calls at all which are not what they should be - all using
the A functions where applicable.
Anyway after deleting all unneccessary code I stil had the problem. Ok, so
I created a brand new test application and didn't get the problem. So was
it a memory stomp ? Thankfully not, because then I started to think what
was different about the code. An then it hit me .......
So what is different about this Control ? Ok, are you ready......the control
has a tooltip. When I disable the tooltip on the Combobox,
IsWindowUnicode()
indicates the control is ASCII. When I enable the tooltip, it is seen by
Windows as Unicode. I might point out that my tests show that this also
occurs for Edit fields as well.
Here is the code that creates the Tooltip, in the hope that someone can see
anything wrong with it. Its years old and I had pretty much forgotten
about it.
HWND vwCreateToolTip(HWND hWnd,
LPSTR lpText)
{
HWND hWndToolTip;
TOOLINFO ti;
/* Create the Window. */
if ((hWndToolTip = CreateWindowEx(0,
TOOLTIPS_CLASS,
NULL,
TTS_ALWAYSTIP,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
hWnd,
NULL,
hInstance,
NULL)) == NULL)
return NULL;
/* Ensure that the Tooltip is Topmost. */
SetWindowPos(hWndToolTip,
HWND_TOPMOST,
0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
ZeroMemory(&ti, sizeof(ti));
/* Define the Tooltip Attributes. */
ti.cbSize = TTTOOLINFO_V1_SIZE;
ti.uFlags = TTF_SUBCLASS | TTF_IDISHWND;
ti.hinst = NULL;
ti.lpszText = lpText;
ti.uId = (UINT)hWnd;
ti.hwnd = hWnd;
/* Set up the Tooltip Attributes. */
SendMessage(hWndToolTip, TTM_ADDTOOL, 0, (LPARAM)&ti);
return hWndToolTip;
}
So in the above code hWnd is actually hWndCombo. Anyway, once the call has
been made hWndCombo is "upgraded" to become a Unicode Window. Destroying
the Tooltip does not cause the Combo to revert to being an ASCII window
though.
Can anyone confirm this finding.
Thanks
Leslie.
Leslie Milburn
2007-09-26 01:28:50 UTC
Permalink
Hi Joe,

No, its a bit more tricky than that.

Firstly sizeof(TCHAR) is a compile time evaluation and is always 1 for
non-unicode builds, so it is meaningless in this sense.

Secondly, GetWindowTextLength returns the number of characters and always
tells me the correct result, eg 20. This is not the number of Bytes that
might actually be used internally, and *thats* the problem.

To finally put my mind at rest, I have subclassed the Combo box and
trapped WM_GETTEXT message. Even though I call GetWindowText() with 7 as the
last parameter, the WM_GETTEXT is actually receiving 14 in wParam. And there
you have an overrun issue. Strangely even if I do a SendMessage
(......WM_GETTEXT, 7, ......) it is still being manipulated internally by
Windows - in other words the SendMessage API is doing "stuff" instead of
just passing it on immediately - I am guessing it is doing an
IsWindowUnicode() call and doubling the size intentionally - it makes sense
if you think about it.

My solution at this stage will be to intercept WM_GETTEXT myself and check
for
Unicode and basically pass on wParam / 2 to Windows.
This way I do not have to mess around with any allocation at all. Of course
this code
will be wrapped in #ifndef _UNICODE in case I recompile using Unicode in the
future
and then totally confuse myself again :-)

So, to conclude, I feel that the Tooltip code is ok having looked at other
examples
via google and no-one here has said otherwise. So I am only left with the
conclusion that it is a bug in Windows itself. I am really keen to know why
the Combobox is "ugraded" to Unicode and its times like this when looking at
the source code would be useful.

Leslie.
Post by Joe Butler
So, is the universal fix to use alloc (GetWindowTextLength() +
sizeof(TCHAR))
zero fill the buffer allocated.
get the window text.
?
Post by Leslie Milburn
Post by Leslie Milburn
Hi all,
Standard ANSI C Win32 application - no Unicode anywhere.
I want to retrieve the first 7 bytes of the current value of a
Combobox field on a window (all owned).
All values in the Combo Dropdown list are approx 20 bytes
in length.
So the code essentially is
TCHAR Buffer[8];
rc = GetWindowText(hWndCombo, Buffer, sizeof(Buffer));
rc = 8 (although it should be 7 according to the documentation as it
should not include the NULL character).
Under Windows XP SP2
rc = 16 and more importantly it is over-running the buffer.
I have tried calling GetWindowTextA() and I have also tried
SendMessage(..., WM_GETTEXT...) but under Windows XP it is ignoring the
buffer size parameter altogether.
I have confirmed that sizeof(Buffer) is correct, and I have even confirmed
sizeof(TCHAR) is 1 byte.
Can anyone reproduce this problem as it is frustrating the hell out of me.
Leslie.
Hi again,
Ok, heres an update on the problem and its a classic, you know you are alive
when you hit this sort of stuff.
I will write it out in full in case anyone else comes across the problem in
months/years to come.
Firstly the return code from GetWindowText() under Windows XP is *correct*,
it was *always* correct - because the Combobox is actually being seen by
Windows as a Unicode Window. I have confirmed it by calling
IsWindowUnicode().
So, passing 7 to the call was actually asking for 7 TCHARS which are double
byte characters and hence the return value of 14 is correct, its the number
of *BYTES* copied (not characters as documented) - and so hence the buffer
overflow.
How could I be so stupid ?? Well as you will see, I was not. I decided to
check the Parent Window Handle and all Child Controls with the
IsWindowUnicode() function. Guess what, all of them *except* the Combobox in
question are seen as ASCII windows. What the #$%& !!!!
Never before have I seen such a thing happen. So I have spent the last 24 or
so hours trawling through 1000's of lines of preprocessor output trying to
find any function calls with a W on the end, like CreateWindowExW() - but
NO, there are no calls at all which are not what they should be - all using
the A functions where applicable.
Anyway after deleting all unneccessary code I stil had the problem. Ok,
so I created a brand new test application and didn't get the problem. So
was it a memory stomp ? Thankfully not, because then I started to think
what was different about the code. An then it hit me .......
So what is different about this Control ? Ok, are you ready......the control
has a tooltip. When I disable the tooltip on the Combobox,
IsWindowUnicode()
indicates the control is ASCII. When I enable the tooltip, it is seen by
Windows as Unicode. I might point out that my tests show that this also
occurs for Edit fields as well.
Here is the code that creates the Tooltip, in the hope that someone can see
anything wrong with it. Its years old and I had pretty much forgotten
about it.
HWND vwCreateToolTip(HWND hWnd,
LPSTR lpText)
{
HWND hWndToolTip;
TOOLINFO ti;
/* Create the Window. */
if ((hWndToolTip = CreateWindowEx(0,
TOOLTIPS_CLASS,
NULL,
TTS_ALWAYSTIP,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
hWnd,
NULL,
hInstance,
NULL)) == NULL)
return NULL;
/* Ensure that the Tooltip is Topmost. */
SetWindowPos(hWndToolTip,
HWND_TOPMOST,
0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
ZeroMemory(&ti, sizeof(ti));
/* Define the Tooltip Attributes. */
ti.cbSize = TTTOOLINFO_V1_SIZE;
ti.uFlags = TTF_SUBCLASS | TTF_IDISHWND;
ti.hinst = NULL;
ti.lpszText = lpText;
ti.uId = (UINT)hWnd;
ti.hwnd = hWnd;
/* Set up the Tooltip Attributes. */
SendMessage(hWndToolTip, TTM_ADDTOOL, 0, (LPARAM)&ti);
return hWndToolTip;
}
So in the above code hWnd is actually hWndCombo. Anyway, once the call
has been made hWndCombo is "upgraded" to become a Unicode Window.
Destroying the Tooltip does not cause the Combo to revert to being an
ASCII window though.
Can anyone confirm this finding.
Thanks
Leslie.
r***@pen_fact.com
2007-09-26 20:41:03 UTC
Permalink
On Wed, 26 Sep 2007 11:28:50 +1000, "Leslie Milburn"
Post by Leslie Milburn
Hi Joe,
No, its a bit more tricky than that.
clip
Post by Leslie Milburn
via google and no-one here has said otherwise. So I am only left with the
conclusion that it is a bug in Windows itself. I am really keen to know why
the Combobox is "ugraded" to Unicode and its times like this when looking at
the source code would be useful.
Well, the upgrade _does_ sound appealing, until you realize the
effects on existing code. Unfortunately, significant parts of
Microsoft seem to not think about such effects. I'm inclined to say it
is Broken as Designed rather than a bug. But the effect on end users
is still bad.
Post by Leslie Milburn
Leslie.
Post by Joe Butler
So, is the universal fix to use alloc (GetWindowTextLength() +
sizeof(TCHAR))
zero fill the buffer allocated.
get the window text.
?
Post by Leslie Milburn
Post by Leslie Milburn
Hi all,
Standard ANSI C Win32 application - no Unicode anywhere.
I want to retrieve the first 7 bytes of the current value of a
Combobox field on a window (all owned).
All values in the Combo Dropdown list are approx 20 bytes
in length.
So the code essentially is
TCHAR Buffer[8];
rc = GetWindowText(hWndCombo, Buffer, sizeof(Buffer));
rc = 8 (although it should be 7 according to the documentation as it
should not include the NULL character).
Under Windows XP SP2
rc = 16 and more importantly it is over-running the buffer.
I have tried calling GetWindowTextA() and I have also tried
SendMessage(..., WM_GETTEXT...) but under Windows XP it is ignoring the
buffer size parameter altogether.
I have confirmed that sizeof(Buffer) is correct, and I have even confirmed
sizeof(TCHAR) is 1 byte.
Can anyone reproduce this problem as it is frustrating the hell out of me.
Leslie.
Hi again,
Ok, heres an update on the problem and its a classic, you know you are alive
when you hit this sort of stuff.
I will write it out in full in case anyone else comes across the problem in
months/years to come.
Firstly the return code from GetWindowText() under Windows XP is *correct*,
it was *always* correct - because the Combobox is actually being seen by
Windows as a Unicode Window. I have confirmed it by calling
IsWindowUnicode().
So, passing 7 to the call was actually asking for 7 TCHARS which are double
byte characters and hence the return value of 14 is correct, its the number
of *BYTES* copied (not characters as documented) - and so hence the buffer
overflow.
How could I be so stupid ?? Well as you will see, I was not. I decided to
check the Parent Window Handle and all Child Controls with the
IsWindowUnicode() function. Guess what, all of them *except* the Combobox in
question are seen as ASCII windows. What the #$%& !!!!
Never before have I seen such a thing happen. So I have spent the last 24 or
so hours trawling through 1000's of lines of preprocessor output trying to
find any function calls with a W on the end, like CreateWindowExW() - but
NO, there are no calls at all which are not what they should be - all using
the A functions where applicable.
Anyway after deleting all unneccessary code I stil had the problem. Ok,
so I created a brand new test application and didn't get the problem. So
was it a memory stomp ? Thankfully not, because then I started to think
what was different about the code. An then it hit me .......
So what is different about this Control ? Ok, are you ready......the control
has a tooltip. When I disable the tooltip on the Combobox,
IsWindowUnicode()
indicates the control is ASCII. When I enable the tooltip, it is seen by
Windows as Unicode. I might point out that my tests show that this also
occurs for Edit fields as well.
Here is the code that creates the Tooltip, in the hope that someone can see
anything wrong with it. Its years old and I had pretty much forgotten
about it.
HWND vwCreateToolTip(HWND hWnd,
LPSTR lpText)
{
HWND hWndToolTip;
TOOLINFO ti;
/* Create the Window. */
if ((hWndToolTip = CreateWindowEx(0,
TOOLTIPS_CLASS,
NULL,
TTS_ALWAYSTIP,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
hWnd,
NULL,
hInstance,
NULL)) == NULL)
return NULL;
/* Ensure that the Tooltip is Topmost. */
SetWindowPos(hWndToolTip,
HWND_TOPMOST,
0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
ZeroMemory(&ti, sizeof(ti));
/* Define the Tooltip Attributes. */
ti.cbSize = TTTOOLINFO_V1_SIZE;
ti.uFlags = TTF_SUBCLASS | TTF_IDISHWND;
ti.hinst = NULL;
ti.lpszText = lpText;
ti.uId = (UINT)hWnd;
ti.hwnd = hWnd;
/* Set up the Tooltip Attributes. */
SendMessage(hWndToolTip, TTM_ADDTOOL, 0, (LPARAM)&ti);
return hWndToolTip;
}
So in the above code hWnd is actually hWndCombo. Anyway, once the call
has been made hWndCombo is "upgraded" to become a Unicode Window.
Destroying the Tooltip does not cause the Combo to revert to being an
ASCII window though.
Can anyone confirm this finding.
Thanks
Leslie.
-----------------------------------------
To reply to me, remove the underscores (_) from my email address (and please indicate which newsgroup and message).

Robert E. Zaret, eMVP
PenFact, Inc.
20 Park Plaza, Suite 478
Boston, MA 02116
www.penfact.com

r***@pen_fact.com
2007-09-25 20:00:43 UTC
Permalink
Thanks for letting us know.

On Tue, 25 Sep 2007 23:02:46 +1000, "Leslie Milburn"
Post by Leslie Milburn
Post by Leslie Milburn
Hi all,
Standard ANSI C Win32 application - no Unicode anywhere.
I want to retrieve the first 7 bytes of the current value of a
Combobox field on a window (all owned).
All values in the Combo Dropdown list are approx 20 bytes
in length.
So the code essentially is
TCHAR Buffer[8];
rc = GetWindowText(hWndCombo, Buffer, sizeof(Buffer));
rc = 8 (although it should be 7 according to the documentation as it
should not include the NULL character).
Under Windows XP SP2
rc = 16 and more importantly it is over-running the buffer.
I have tried calling GetWindowTextA() and I have also tried
SendMessage(..., WM_GETTEXT...) but under Windows XP it is ignoring the
buffer size parameter altogether.
I have confirmed that sizeof(Buffer) is correct, and I have even confirmed
sizeof(TCHAR) is 1 byte.
Can anyone reproduce this problem as it is frustrating the hell out of me.
Leslie.
Hi again,
Ok, heres an update on the problem and its a classic, you know you are alive
when you hit this sort of stuff.
I will write it out in full in case anyone else comes across the problem in
months/years to come.
Firstly the return code from GetWindowText() under Windows XP is *correct*,
it was *always* correct - because the Combobox is actually being seen by
Windows as a Unicode Window. I have confirmed it by calling
IsWindowUnicode().
So, passing 7 to the call was actually asking for 7 TCHARS which are double
byte characters and hence the return value of 14 is correct, its the number
of *BYTES* copied (not characters as documented) - and so hence the buffer
overflow.
How could I be so stupid ?? Well as you will see, I was not. I decided to
check the Parent Window Handle and all Child Controls with the
IsWindowUnicode() function. Guess what, all of them *except* the Combobox in
question are seen as ASCII windows. What the #$%& !!!!
Never before have I seen such a thing happen. So I have spent the last 24 or
so hours trawling through 1000's of lines of preprocessor output trying to
find any function calls with a W on the end, like CreateWindowExW() - but
NO, there are no calls at all which are not what they should be - all using
the A functions where applicable.
Anyway after deleting all unneccessary code I stil had the problem. Ok, so I
created a brand new test application and didn't get the problem. So was it a
memory stomp ? Thankfully not, because then I started to think what was
different about the code. An then it hit me .......
So what is different about this Control ? Ok, are you ready......the control
has a tooltip. When I disable the tooltip on the Combobox, IsWindowUnicode()
indicates the control is ASCII. When I enable the tooltip, it is seen by
Windows as Unicode. I might point out that my tests show that this also
occurs for Edit fields as well.
Here is the code that creates the Tooltip, in the hope that someone can see
anything wrong with it. Its years old and I had pretty much forgotten about
it.
HWND vwCreateToolTip(HWND hWnd,
LPSTR lpText)
{
HWND hWndToolTip;
TOOLINFO ti;
/* Create the Window. */
if ((hWndToolTip = CreateWindowEx(0,
TOOLTIPS_CLASS,
NULL,
TTS_ALWAYSTIP,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
hWnd,
NULL,
hInstance,
NULL)) == NULL)
return NULL;
/* Ensure that the Tooltip is Topmost. */
SetWindowPos(hWndToolTip,
HWND_TOPMOST,
0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
ZeroMemory(&ti, sizeof(ti));
/* Define the Tooltip Attributes. */
ti.cbSize = TTTOOLINFO_V1_SIZE;
ti.uFlags = TTF_SUBCLASS | TTF_IDISHWND;
ti.hinst = NULL;
ti.lpszText = lpText;
ti.uId = (UINT)hWnd;
ti.hwnd = hWnd;
/* Set up the Tooltip Attributes. */
SendMessage(hWndToolTip, TTM_ADDTOOL, 0, (LPARAM)&ti);
return hWndToolTip;
}
So in the above code hWnd is actually hWndCombo. Anyway, once the call has
been made hWndCombo is "upgraded" to become a Unicode Window. Destroying the
Tooltip does not cause the Combo to revert to being an ASCII window though.
Can anyone confirm this finding.
Thanks
Leslie.
-----------------------------------------
To reply to me, remove the underscores (_) from my email address (and please indicate which newsgroup and message).

Robert E. Zaret, eMVP
PenFact, Inc.
20 Park Plaza, Suite 478
Boston, MA 02116
www.penfact.com
Loading...