The evolution of the text size limits related to the standard static control

Michael Quinlan wondered about the text size limits related to the standard static control

We start with the resource format, since that was the limiting factor in the original problem. The original 16-bit resource format represented strings as null-terminated sequences of bytes, so in theory they could have been arbitrarily large. However, 16-bit string resources were limited to 255 characters because they used a byte count for string length. My guess is that the resource compiled took this as a cue that nobody would need strings longer than 255 characters, so it avoided the complexity of having to deal with a dynamic string buffer, and when it needed to parse a string in the resource file, it did so into a fixed-size 256-byte buffer.

I happen to still have a copy of the original 16-bit resource compiler, so I can actually verify my theory. Here's what I found:

There was a "read next token" function that placed the result into a global variable. Parsing was done by asking to read the next token (making it the current token), and then and then studying the current token. If the token was a string, the characters of the string went into a buffer of size MAXSTR + 1. And since string resources have a maximum length of 255, MAXSTR was 255.

Although the limit of 255 characters did not apply to dialog controls, the common string parser stopped at 255 characters. In theory, the common string parser could have used dynamic memory allocation to accommodate the actual string length, but remember that we're 16-bit code here. Machines had 256KB of memory, and no memory block could exceed 64KB. Code in this era did relatively little dynamic memory allocation; static memory allocation was the norm. It's like everybody was working on an embedded system.

Anyway, that's where the 255-character limit for strings in resource files comes from. But that's not a limit of the resource file format or of static text controls. It's just a limit of the resource compiler. You can write your own resource compiler that generates long strings if you like.

Okay, so what about the static text control? The original 16-bit static text control had a text size limit of 64KB because 16-bit. This limit carried forward to Windows 95 because the static text control in Windows 95 was basically a 16-bit control with some 32-bit smarts.

On the other hand, Windows NT's standard controls were 32-bit all the way through (and also Unicode). The limits consequently went up from 64KB to 4GB. Some messages needed to be revised in order to be able to express strings longer than 64KB, For example, the old EM_GET­SEL message returned the start and end positions of the selection as two 16-bit integers packed into a single 32-bit value. This wouldn't work for strings longer than 65535 characters, so the message was redesigned so that the wParam and lParam are pointers to 32-bit integers that receive the start and end of the selection.

Anyway, now that the 16-bit world is far behind us, we don't need to worry about the 64KB limit for static and edit controls. The controls can now take all the text you give it.²

¹ And then for some reason Erkin Alp Güney said that I'm "employed as a PR guy." I found this statement very strange, because not only am I not employed as a PR guy, I have basically no contact with PR at all. The only contact I do have is that occasionally they will send me a message saying that they are upset at something I wrote. I remember that they were very upset about my story that shared some trivia about the //build 2011 conference because it (horrors) talked about some things that went wrong. (And as Tom West noted, it wouldn't seem to be a good idea for PR to employ someone with the social skills of a thermonuclear device.)

² Well, technically no. If you give a string longer than 4GB, then it won't be able to handle that. So more accurately, it can handle all the text you would give it, provided you're not doing something ridiculous. I mean, you really wouldn't want to manipulate 4GB of data in the form of one giant string. And no human being would be able to read it all anyway.

Comments (10)
  1. Clockwork-Muse says:

    Well, you _could_ …. it’d just take you about 19 years to do it…

    2 ^ 32 characters.
    5 characters per average word, plus 1 space (ignoring punctuation).
    200-230 word-per-minute average reading comprehension speed
    60 minutes in a hour
    8 ‘working’ hours per day.
    365.25 days per year.

    (2 ^ 32) / (5 + 1) / 215 / 60 / 8 / 365.25 = ~19 years

    … so it’s conceivable that somebody whose job was mostly reading/collating paperwork has read that many words over their career (probably longer than 20 years, though).

    1. Kevin says:

      Raymond, I think you have to bring back the Nitpicker’s Corner for this one!

  2. Ivan k says:

    Some install program surprisingly (to me) asked me if it could just go ahead and just change maxpath. Hahaha… No.

    1. Mike Dimmick says:

      It’s possible your installer was trying to change the group policy setting that enables OS support for longer-than-MAX_PATH paths in legacy APIs. For this to work, a) you must be running the Anniversary Update (build 14393 or later), b) the Group Policy has to be changed and c) programs have to opt-in via an app manifest. .NET apps targeting framework version 4.6.1 or earlier *also* have to opt in via a setting in their .exe.config files (before 4.6.2, the .NET Framework itself checked for path-too-long and threw an exception without asking the OS what it thought). See

      Of course it would be incredibly bad if installers changed that setting for you without understanding what they were doing. It’s behind a group policy setting because it’s a bit incomplete – some parts of CMD.EXE reportedly work properly, others don’t.

  3. alegr1 says:

    But how do I open those ridiculously long log files?

  4. Adrian says:

    It seems there are other places that the standard static control text size could be limited. For example, when painting, it presumably uses something like TextOutW, which appears to have an undocumented limit of 32,767 WCHARs. I suppose it might use DrawTextW, but I expect that would issue multiple TextOutW (or equivalent) calls for multiple lines, so it might be unbounded in total length, but each line would be bounded by the 32K character limit.

    Yeah, lines of 32K-character lines in a static text control are highly unlikely. On the other hand, you could have a tiny font, a window that spans multiple super-high DPI monitors, and a bunch of those WCHARs could be surrogate pairs and combining characters that take little to no horizontal space. Just saying.

  5. 640k says:

    Simple math dictates, that when 128-bit windows comes, we will be able to store 2^64 bytes of text in static controls.

  6. SimonRev says:

    I once used a bit of software that created files that directly corresponded with object names in the project. This same software helpfully tried to make sure that paths never exceeded 200 bytes (not sure where they got the 200 bytes from).

    The upshot was that it was very easy to create projects on one machine that were not portable to another machine because the resulting paths were too long on the 2nd machine. (It also helpfully refused to open such projects with an “invalid name” error).

  7. DWalker07 says:

    It’s funny that someone assumes that a Microsoft PR person would have the technical expertise to write a blog post like the linked post. It’s possible, but after reading that post, “PR person” is not the first thought that would come to me….

  8. Zenith says:

    Too late to ask this, I suppose, but does that have anything to do with how Labels have their text saved to a resx file in Visual Studio? I have a habit of deleting that worthless file as all it ever contained was a location for my timers and other non-controls. And then, once, I had a long block of text in a Label that went poof when I deleted that file. Apparently, at some arbitrary length, VS moves Label text out of the form designer’s InitializeComponent() block and into that resx file. I’ve tried everything that I could find to stop this from happening but there doesn’t seem to be any way to do so without assigning the text elsewhere or using a disabled multiline TextBox instead.

Comments are closed.

Skip to main content