CEdit control maximum length? (in characters it can display) - mfc

What is the maximum length for the text string contained in a CEdit control in MFC? I get a beep when trying to add a character after the character 30001 is this documented anywhere? Can I display longer texts in a CEdit? Should I use another control?
As "Windows programmer" says down below, the text length limit is not the same when the user types as when we programatically set the text using SetWindowText. The limit for setting a text programatically is not mentioned anywhere. The default text lentgth limit for the user typing is wrong. (see my own post below).
I'm guessing that after I call pEdit->SetLimitText(0) the limit for both programatically and user input text length is 7FFFFFFE bytes. Am I right?
In vista, when pasting text longer than 40000 characters into a CEdit, it becomes unresponsive. It does not matter if I called SetLimitText(100000) previously.

I found the documentation is wrong when mentioning the default size for a single line CEdit control in vista.
I ran this code:
CWnd* pWnd = dlg.GetDlgItem(nItemId);
CEdit *edit = static_cast<CEdit*>(pWnd); //dynamic_cast does not work
if(edit != 0)
{
UINT limit = edit->GetLimitText(); //The current text limit, in bytes, for this CEdit object.
//value returned: 30000 (0x7530)
edit->SetLimitText(0);
limit = edit->GetLimitText();
//value returned: 2147483646 (0x7FFFFFFE)
}
the documentation states:
Before EM_SETLIMITTEXT is called, the
default limit for the amount of text a
user can enter in an edit control is
32,767 characters.
which is apparently wrong.

You can find out what the maximum is for your control by calling CEdit::GetLimitText() on your control. This returns the maximum size for character data in bytes. You can change the maximum size using the CEdit::SetLimitText() function.
The SetLimitText() function is equivalent to sending an EM_SETLIMITTEXT message. The documentation for that message gives the maximum sizes that can be used, but since these are MSDN links that will probably be broken by tomorrow, I'll copy the relevant information :)
The UINT parameter is interpreted as:
The maximum number of TCHARs the user
can enter. For ANSI text, this is the
number of bytes; for Unicode text,
this is the number of characters. This
number does not include the
terminating null character. Rich edit
controls: If this parameter is zero,
the text length is set to 64,000
characters.
Edit controls on Windows NT/2000/XP:
If this parameter is zero, the text
length is set to 0x7FFFFFFE characters
for single-line edit controls or –1
for multiline edit controls.
Edit controls on Windows 95/98/Me: If
this parameter is zero, the text
length is set to 0x7FFE characters for
single-line edit controls or 0xFFFF
for multiline edit controls.
Also, from the Remarks section:
Before EM_SETLIMITTEXT is called, the
default limit for the amount of text a
user can enter in an edit control is
32,767 characters.
Edit controls on Windows NT/2000/XP:
For single-line edit controls, the
text limit is either 0x7FFFFFFE bytes
or the value of the wParam parameter,
whichever is smaller. For multiline
edit controls, this value is either –1
bytes or the value of the wParam
parameter, whichever is smaller.
Edit controls on Windows 95/98/Me: For
single-line edit controls, the text
limit is either 0x7FFE bytes or the
value of the wParam parameter,
whichever is smaller. For multiline
edit controls, this value is either
0xFFFF bytes or the value of the
wParam parameter, whichever is
smaller.
I assume they meant 0xFFFFFFFF instead of -1 in the second paragraph there...

"(in characters it can display)" != "when trying to add a character".
"when trying to add a character" == "The maximum number of TCHARs the user can enter"
unless you mean programmatically trying to add a character.
"0x7FFFFFFE characters" != "0x7FFFFFFE bytes"
except sometimes, a fact which the quoted MSDN text understands sometimes.
I'll bet no one knows the answer to the original question. But "0x7FFFFFFE bytes" is likely one of many limits.

Related

C++ Store Edit Box Value Into A Int

I need to Read the value that is typed into a EditBox and save into into a Int.
Does anyone know how to do this?? this is the code i have so far..
case EditAge: {
if (HIWORD(wParam) == EN_CHANGE)
Well, that's a start, but did you even try to retrieve the text? Or do you have issues converting the text to a number? For future questions, try to be more specific. You're most likely looking for something like this line (don't forget to check to see if you're in the right text box!):
GetDlgItemText(dialoghandle, LOWORD(wParam) /* the control id */, text /* pointer where the text should go */, 256 /* max number of elements */);
Once you've got the text, you can use e.g. strtol() to parse the string and retrieve a number.
Edit:
You could actually use GetDlgItemInt(), documented here, to retrieve an integer right away.

Handling keyboard input in win32, WM_CHAR or WM_KEYDOWN/WM_KEYUP?

So in the text editor program that i've been working on, I've used WM_CHAR to process input from the keyboard. However, I found that some of the character mesages are not recorded. For example, if I use [shift]+ number key to type a symbol such as % or &, some re recorded while others such as [shift]+9 (which results in ')'), are not recorded. So, I'm wondering if I should use WM_KEYDOWN/WMKEYUP pair to handle keyboard input. I once wrote a keylogger in assembly(actually it was just a tutorial that i was trying out) and had used WM_KEYDOWN/WM_KEYUP pairs and that worked out quite good. So, should I move on to this, or is it something unusual that is happening with my program?
Thanks,
Devjeet
This is really a long reply to your comment above, but putting it in an answer because it's too long for a comment :)
The core issue to understand here is that keys and characters are not quite the same thing. Some (but not all) keys generate characters; some keys generate different characters depending on shift or other keyboard state. And to implement an editor, you need to handle both textual input and also non-textual keyboard input like arrow keys. Now the long-winded version, picking off from what seems to be an incorrect assumption:
Apparently, windows works in really strange ways. [...] It seems that when you press [shift]+9, windows sends a VK_LEFT in the wParam of message WM_CHAR
Sounds like you might be mixing two things up here. The thing with WM_CHAR is that it gives you character codes for textual characters: so if someone presses the 9 key, you'll get '9'. If someone presses SHIFT+9, Windows will take the shift state into account - and you get '(' (if using US keyboard). But you won't ever get a WM_CHAR for arrow keys, HOME, END, and so on, since they are not textual characters. WM_KEYDOWN, on the other hand, does not deal in characters, but in VK_ codes; so pressing 9 gives you VK_9 regardless of shift state; and left arrow gives you VK_LEFT - again regardles of shift state.
The things is that WM_CHAR and WM_KEYDOWN both give you two parts to the overall input picture - but you really have to handle both to get the full picture. And have to be aware that the wParam is a very different thing in both cases. It's a character code for WM_CHAR, but a VK_ code for WM_KEYDOWN. Don't mix the two.
And to make things more confusing, VK_ values share the same values as valid characters. Open up WinUser.h (it's in the include dir under the compiler installation dir), and look for VK_LEFT:
#define VK_LEFT 0x25
Turns out that 0x25 is also the code for the '%' character (see any ascii/unicode table for details). So if WM_CHAR gets 0x25, it means shift-5 was pressed (assuming US keyboard) to create a '%'; but if WM_KEYDOWN gets 0x25, it means left arrow (VK_LEFT) was pressed. And to add a bit more confusion, the Virtual Key codes for the A-Z keys and 0-9 keys happen to be the same as the 'A'-'Z' and '0'-'9' characters - which makes it seem like chars and VK_'s are interchangable. But they're not: the code for lower case 'a', 0x61, is VK_NUMPAD1! (So getting 0x61 in WM_CHAR does mean 'a', getting it in WM_KEYDOWN means NUMPAD1. And if a user does hit the 'A' key in unshifted state, what you actually get is first a VK_A (same value as 'A') in WM_KEYDOWN, which gets translated to WM_CHAR of 'a'.)
So tying all this together, the typical way to handle keyboard is to use all of the following:
Use WM_CHAR to handle textual input: actual text keys. wParam is the character that you want to append to your string, or do whatever else with. This does all the shift- processing for you.
Use WM_KEYDOWN to handle 'meta' keys - like arrow keys, home, end, page up, and so on. Pass all the A-Z/0-9 values through, the default handling will turn them into WM_CHARs that you can handle in your WM_CHAR handler. (You can also handle numpad keys here if you want to use them for special functionality; otherwise they 'fall through' to end up as numeric WM_CHARs, depending on numlock state. Windows takes care of this, just as it handles shift state for the alphabetic keys.)
If you want to handle ALT- combos explicitly (rather than using an accelerator table), you'll get those via WM_SYSKEYDOWN.
I think there are some keys that might show up in both - Enter might show up as both a WM_KEYDOWN of VK_RETURN and as either \r or \n WM_CHAR - but my preference would be to handle it in WM_KEYDOWN, to keep editing key handling separate from text keys.
Spy++ will show you the messages being sent to a window, so you can experiment and see what messages are appropriate for your application.
If you have Visual Studio installed, it should be in your Start menu, under Programs -> Microsoft Visual Studio -> Visual Studio Tools -> Spy++.
WM_CHAR
WM_KEYDOWN
The helpful message above inspired me to create this snippet, which gives you a human-readable indication of what key was pressed from any WM_KEYDOWN/WM_KEYUP/WM_SYSKEYDOWN/WM_SYSKEYUP independent of the state of the modifier keys.
// get the keyboard state
BYTE keyState[256];
GetKeyboardState(keyState);
// clear all of the modifier keys so ToUnicode will ignore them
keyState[VK_CONTROL] = keyState[VK_SHIFT] = keyState[VK_MENU] = 0;
keyState[VK_LCONTROL] = keyState[VK_LSHIFT] = keyState[VK_LMENU] = 0;
keyState[VK_RCONTROL] = keyState[VK_RSHIFT] = keyState[VK_RMENU] = 0;
// convert the WM_KEYDOWN/WM_KEYUP/WM_SYSKEYDOWN/WM_SYSKEYUP to characters
UINT scanCode = (inLParam >> 16) & 0xFF;
int i = ToUnicode(inWParam, scanCode, keyState, outBuf, inOutBufLenCharacters, 0);
outBuf[i] = 0;
By modifying the keyState array so that all the modifier keys are clear, ToUnicode will always output the unshifted key you pressed. (So, on the English keyboard you'll never get '%' but always '5') as long as it's a human readable key. You still have to do the VK_XXX checking to sense the arrow and other non-human readable keys however.
(I was trying to rig up a user editable "hot key" system in my app, and the distinction between WM_KEYXXX and WM_CHAR was making me nuts. The code above solved that problem.)

How to get displayed width of a string?

When you have non-fixed width characters (such as \t) in a string , or escape codes, such as those for ANSI color (such as \1xb[31m), these characters add to the .length() of an std::string, but do not add to the displayed length when printed.
Is there any way in C++ to get the displayed width of a string in *nix?
For instance:
displayed_width("a\tb") would be 4 if the displayed tab width is 2
displayed_width("\1xb[33mGREEN") would be 5
Most commonly, a tab asks the terminal program to move the cursor to a column that's a multiple of 8, though many terminal programs let you configure that. With such behaviour, how much width a tab actually adds depends on where the cursor was beforehand relative to the tab stops. So, simply knowing the string content is not enough to calculate a printable width without some assumption or insight regarding prior cursor placement and tab stops.
Non-printable codes also vary per terminal type, though if you only need ANSI colour then that's pretty easy. You can move along the string counting characters; when you see an ESCAPE skip through to the terminating m. Something like (untested):
int displayed_width(const char* p)
{
int result = 0;
for ( ; *p; ++p)
{
if (p[0] == '\e' && p[1] == '[')
while (*p != 'm')
if (*p)
++p;
else
throw std::runtime_error("string terminates inside ANSI colour sequence");
else
++result;
}
return result;
}
Nothing built in. The "displayed width" of the tab character is an implementation detail, as are console escape sequences. C++ doesn't care about platform-specific things like that.
Is there something in particular you're trying to do? We may be able to suggest alternatives if we know what particular task you're working on.
Not with standard methods to my knowledge. C++ does not know about terminals.
My guess would be to use NCURSES for that. Dunno if boost has something up the sleeve for that though.
Display length on what device? A console that uses a fixed-width font? A window that uses a proportional font? This is highly device-dependent question. There is no fixed answer. You will have to use the tools associated with the target output device.

Get text using SendMessage() C++

I am trying to get text from a textbox in a specific window. For this I'm using SendMessage Api function, I dont know if this is the corect way:
SendMessage(hwnd, WM_GETTEXT, 0, 0);
But I dont know how to print the text. For the argument 3 and 4 in msdn site it says: Additional message-specific information. So i dont know if I need to pass something else beside 0. I tried this also:
SendMessage(hwnd, WM_GETTEXT, sizeof(text), LPARAM(text));
But it prints the name of the textbox, I need to retrieve the text inside the box?
How can I do this? Is SendMessage() the correct API function to use ?
Thank you.
edit:
I omit to say, I am enumerating the child windows from a window, and for me it looks like a textbox, where you have to type a name. I am retrieving the username of a Instant messaging window so I cant compare it to a string, is that a textbox ?
You should use GetWindowText. More information here.
Read the MSDN documentation again. It does NOT say "Additional message-specific information" for those parameters:
wParam The maximum number of
characters to be copied, including the
terminating null character.
ANSI applications may have the string
in the buffer reduced in size (to a
minimum of half that of the wParam
value) due to conversion from ANSI to
Unicode.
lParam A pointer to the buffer that
is to receive the text.
This code works for local only:
char *szText;
szText = (char *)GlobalAlloc(GPTR, 255);
SendMessage(hEditControl, WM_GETTEXT, 255, (LPARAM)szText);
MessageBox(hWnd, szText, "It's your message", MB_OK | MB_TOPMOST);
GlobalFree((HGLOBAL)szText);

How to print many format strings into window?

After successfully solve this problem how to print a format string into window, another problem comes to me.
If there are many format strings, how to print them into window? For example below:
sprintf(buf, formatString-1...);
SendMessage(hwnd, WM_SETTEXT, NULL, (LPARAM)buf);
...
sprintf(buf, formatString-2...);
SendMessage(hwnd, WM_SETTEXT, NULL, (LPARAM)buf);
...
sprintf(buf, formatString-3...);
SendMessage(hwnd, WM_SETTEXT, NULL, (LPARAM)buf);
...
Notice that only formatString-3 is printed into window, while i want to put them all into window. How to do this?(PS: Please Do not use buf concatenate) Thank you!~
Are you trying to produce a console-style or log-style window, with multiple lines of text, one after the other?
If so, simplest approach is to pick a control that will do this for you. Something like a static (usually used for labels) typically is only useful for one string at a time. If you want to display more than one line of output, your two main options are:
Listbox control: add items to the end using LB_ADDSTRING. (You may want to follow that with LB_SETCURSEL or similar to select the last item, so that as items are added to the end, it will scroll to show the last item.)
Read-only Multi-line Edit control: append text to the end using the technique outlined here on MSDN. Note that with this approach, you need to supply the "\r\n" yourself to create a new line.
Each WM_SETTEXT message overwrites the previous one. That's why you only observe the effects of the final message.
Although you state that you don't want to concatenate the buffer before sending the WM_SETTEXT message, that's the only option with WM_SETTEXT.
If you have an edit control then you can insert text using the EM_REPLACESEL message.