• The Old New Thing

    How do I disable windowless control support in dialog boxes?

    • 12 Comments

    A customer wanted to know how to disable windowless control support in dialog boxes. "The customer has a CommandButton ActiveX control on his dialog box, and using Get­Dlg­Item to get the window handle of the command button succeeded with VC 6.0, but when compiled with VC 9.0, it does not create a window. I'm guessing that this is caused by Dialog­Box's support for windowless controls. Is it possible to disable support for windowless controls?"

    The question on its face is somewhat puzzling, because dialog boxes don't "support" or "not support" windowless controls. It's like asking, "I want rice that doesn't support meat. My customer is a vegetarian and cannot eat meat." Rice doesn't support meat, and it doesn't not-support meat. If you don't want meat, then don't add meat. And if you don't want windowless controls on your dialog box, then don't create windowless controls.

    I was also not sure what the customer meant by CommandButton, because Win32 command buttons are not ActiveX controls. The customer must be referring to something else also called Command­Button, in which case the customer should also consult the documentation for that something else to see if there's a way to control its windowed/windowless behavior.

    The customer liaison gave some more details: "My customer uses Get­Dlg­Item to get the handle of a specific window. This method worked in VC 6.0 since VC 6.0 doesn't support windowless controls. But VC 9.0 added support for windowless controls in dialog boxes, which breaks my customer's code. Is there a way to disable support for windowless controls in dialog boxes?"

    It took a few more questions, but eventually we figured out that the customer was not using raw Win32 dialog boxes (as Dialog­Box suggested in the original question) but rather MFC dialog boxes, and the CommandButton in question is a Microsoft Forms 2.0 CommandButton control.

    "The customer simply wants to continue using his code without modification. He is already using the Microsoft Forms 2.0 CommandButton control, and he is already using Get­Dlg­Item to obtain its handle, but that technique no longer works."

    The pieces started to fall into place, and somebody from the Visual Studio team provided an explanation: The version of MFC which comes with Visual Studio 2000 added support for hosting windowless ActiveX controls. By default, the MFC hosting code permits controls to be added as windowless controls if the control requests it. To force all controls to be windowed, you need to provide a custom class which derives from COle­Control­Site and overrides IOle­In­Place­Site­Windowless::Can­Windowless­Activate to return S_FALSE. Then override the dialog's CWnd::Create­Control­Site method to return an instance of this class instead of the default control site.

    I haven't actually tested this to see if it works, but the customer didn't come back, so either it worked, or they decided that we were jerks and didn't want to waste their time with us any more.

  • The Old New Thing

    Getting in on the action while it's still there

    • 12 Comments

    Remember day trading? All the cool people were doing it. Glamour stories of people who tripled or quadrupled their stake in a single day. With all this money available for the taking, you'd be a fool not to be day-trading!

    During the era of day trading frenzy, I got a particular chuckle out of one PC manufacturer who produced a Precision Online Trading Workstation, equipped with dual monitors and dual processors and preloaded with financial software, so you can see more stock quotes, crunch those numbers faster, and lose more money more quickly than you ever thought possible. I imagined the logic that went into this product:

    "There's a lot of stupid people out there. Stupid people who are going to lose all their money one way or another. They may as well lose some of it to us."

  • The Old New Thing

    Why waste your money on the car when it's the sound system you care about?

    • 20 Comments

    There is apparently a subculture of people who decide to economize on the car part of the "loud stereo in car" formula (since they really don't care about the car—it's all about the music) and put their loud stereo on the back of a bicycle instead.

    This quotation from the article caught my attention:

    "People say, 'It's the next best thing to having a system in a car.' But it's better because you don't even have to roll down the windows."

    I had been unsure what to think about people who drive down the street with their stereos blaring. Are they audiophiles who prefer their music loud? Or are they jerks who like to annoy other people with loud music? That quotation sort of settles it.

  • The Old New Thing

    Why does saving a file in Notepad fire multiple FindFirstChangeNotification events?

    • 9 Comments

    Many people have noticed that the Read­Directory­ChangesW and Find­First­Change­Notification functions (and therefore their BCL equivalent File­System­Watcher and WinRT equivalent Storage­Folder­Query­Result) fire multiple FILE_ACTION_MODIFIED events when you save a file in Notepad. Why is that?

    Because multiple things were modified.

    Notepad opens the file for writing, writes the new data, calls Set­End­Of­File to truncate any excess data (in case the new file is shorter than the old file), then closes the handle. Two things definitely changed, and a third thing might have changed.

    • The file last-modified time definitely changed.
    • The file size definitely changed.
    • The file last-access time might have changed.

    It's therefore not surprising that you got two events, possibly three.

    Remember the original design goals of the Read­Directory­ChangesW function: It's for letting an application cache a directory listing and update it incrementally. Given these design goals, filtering out redundant notifications in the kernel is not required aside from the performance benefits of reduced chatter. In theory, Read­Directory­ChangesW could report a spurious change every 5 seconds, and the target audience for the function would still function correctly (albeit suboptimally).

    Given this intended usage pattern, any consumer of Read­Directory­ChangesW needs to accept that any notifications you receive encompass the minimum information you require in order to keep your cached directory information up to date, but it can contain extra information, too. If you want to respond only to actual changes, you need to compare the new file attributes against the old ones.

    Bonus chatter: Actually, the two things that changed when Notepad set the file size are the allocation size and the file size (which you can think of as the physical and logical file sizes, respectively). Internally, this is done by two separate calls into the I/O manager, so it generates two change notifications.

  • The Old New Thing

    Fixups are not the same as rewriting code, they're just fixups

    • 18 Comments

    Classically speaking, a linker cannot rewrite the code the compiler generated; its job is merely to resolve symbols. Of course, resolving symbols means that references to those symbols in the code generated by the compiler turn from "I don't know" to "Here it is." Somebody named George appeared to be confused by this, believing that all changes by the linker counted as "rewriting code."

    Obviously if the linker weren't allowed to change anything at all, there wouldn't be much point to having a linker. For example, you wouldn't be able to access functions or variables in a separate compilation unit (for example, from a library) because the compiler doesn't know what the final address is; that's what the linker is supposed to figure out. (Indeed, if function-level linking is enabled, then even calls within a compilation unit are left as insert address here.) The linker resolves symbols and patches up code references that used to say insert address here so that they contain the actual address.

    I think George took my statement a bit too literally. The linker can't change a direct call to an indirect call; that's not something that the compiler told the linker how to do. All the linker can do is patch up insert address here fixups. It can't say "Oh, I'm going to take your two mov instructions and reverse the destination registers, and then flip the arguments to the subsequent sub instruction." (I'm talking about classical linking; the introduction of link-time code generation further blurs the line between the compiler and the linker.)

    George also made the common mistake not only of calling this Web site a "document from MSDN" but also applying the same description to a Microsoft Systems Journal article from 1997. The back issues of MSJ are included in MSDN as a courtesy. Neither the back issues nor the contents of this Web site are under MSDN editorial control.

  • The Old New Thing

    Isn't there a race condition in GetFileVersionInfoSize?

    • 18 Comments

    In response to my explanation of what the lpdwHandle parameter in Get­File­Version­Info­Size is used for, Steve Nuchia wonders if there's a race condition between the time you get the size and the time you ask for the data.

    Yes, there is a race condition, but calling the function in a loop won't help because the Get­File­Version­Info function does not report that the buffer is too small to hold all the version data. It just fills the buffer as much as it can and truncates the rest.

    In practice, this is not a problem because you are usually getting the versions of files that you expect to be stable. For example, you might be obtaining the version resources of the files your application is using in order to show them in diagnostics. The file can't change because you're preventing them from changing by using them. In the case that the file changes out from under you, then yes, you will sometimes get partial data.

    While I'm on the subject of Get­File­Version­Info, I figured I'd mention that there's a good amount of code in Ver­Query­Value to handle the following scenario:

    • On Windows NT 3.1, a program calls Get­File­Version­Info to obtain a file version information block.
    • The program writes the information block to a file.
    • The file is preserved in amber for millions of years.
    • A curious scientists discovers the file version information block, loads it from the file back into memory, and calls Ver­Query­Value.

    The modern implementation of Ver­Query­Value still understands the file version information block created by all previous versions of Windows, and if you hand it one of those frozen-in-amber information blocks, it still knows how to extract information from it. It may not be able to do as good a job due to the lack of appropriate buffer space, but it does at least as well as the version of Windows the file version information block was originally generated from. I have no idea whether anybody actually takes advantage of this behavior, but since persisting the file version information block was never explicitly disallowed in the documentation, one could argue that doing so was legal, and the code therefore needs to be ready for it. (Heck, even if it were explicitly disallowed, there would still be a good chance that there's somebody who's doing it.)

    What Ver­Query­Value doesn't handle is people who hand it a file version information block that never came from Get­File­Version­Info in the first place.

  • The Old New Thing

    What is the default size of the Recycle Bin, and how can an administrator control the size of the Recycle Bin?

    • 13 Comments

    A customer was setting up a file server to which they intended to redirect all their employees' documents. They were concerned about the amount of disk space used by all the Recycle Bins on that server.

    Is there a fixed default size for the Recycle Bin, or is it based on the size of the disk? Is there a way we can change the default size for the Recycle Bin?

    The customer is concerned that a user with a small quota on a large drive may end up filling their quota with Recycle Bin content and have no space left for their documents. For example, suppose you have a 1TB drive and each user has a 15 GB quota. If the Recycle Bin were based on disk size, and the Recycle Bin were set to use five percent of the disk, then that would give each user 5% × 1 TB = 51.2 GB of Recycle Bin, which is larger than their quota. Users can fill their Recycle Bin and have no room for documents!

    Fortunately, it doesn't work that way. The Recycle Bin calculations are always based on the disk quota, not the disk size. In the above example, each user's Recycle Bin would be 5% × 15 GB = 768 MB.

    Now as to what the default is, that's a trickier question.

    Up through Windows XP, the default Recycle Bin was ten percent of the user's quota on the underlying volume. Starting in Windows Vista, the algorithm was tweaked, and the default size is ten percent of the first 40 GB of quota, and five percent of any quota above 40 GB. (Note that future versions of Windows may tweak the defaults. This is provided for informational purposes, not contractual.)

    If you don't like the default, you can set an explicit maximum value by policy. If you are willing to live a little dangerously, you can dig under the covers and tweak values on a per-folder basis. Note that once you dig under the covers, you are in unsupported territory, so if it stops working (or starts misbehaving), then you're on your own.

  • The Old New Thing

    Enumerating all the ways of making change

    • 29 Comments

    Today's Little Program enumerates all the ways of making change for a particular amount given a set of available denominations.

    The algorithm is straightforward. To make change for a specific amount from a set of available denominations, you can take one denomination and decide how many of those you want to use. Then use the remaining denominations to make change for the remainder.

    For example, if the available coins have values [1, 5, 10, 25] and you want to make change for 60 cents, you first decide how many 25-cent pieces you want to use. If you use none, then you need to make change for 60 cents using just [1, 5, 10]. If you use one, then you need to make change for 35 cents using just [1, 5, 10]. And if you use two, then you need to make change for 10 cents using just [1, 5, 10].

    (We use the largest coin first to reduce the number of dead ends, like asking "Please make change for 83 cents using only 10-cent coins.")

    function MakeChange(coins, total, f) {
     if (total == 0) { f([]); return; }
     if (coins.length == 0) return;
    
     var coin = coins[coins.length - 1];
     var remaining = coins.slice(0, -1);
     var used = [];
     for (var target = total; target >= 0; target -= coin) {
      MakeChange(remaining, target, function(s) {
       f(used.concat(s));
      });
      used.push(coin);
     }
    }
    
    MakeChange([1, 5, 10, 25], 60, console.log.bind(console));
    

    First, we take care of some base cases. To make change for zero cents, we simply use zero coins. And it's not possible to make change for a nonzero amount with no coins.

    Otherwise, we take the highest denomination coin and try using zero of them, then one of them, and so on, until we exceed the total amount necessary.

    There are related problems, such as determining whether a particular amount of change can even be made, given a collection of denominations and calculating the number of ways change can be made rather than enumerating them. But I like enumeration problems.

  • The Old New Thing

    When will GetSystemWindowsDirectory return something different from GetWindowsDirectory?

    • 30 Comments

    Most of the time, the Get­Window­Directory returns the Windows directory. However, as noted in the documentation for Get­System­Windows­Directory:

    With Terminal Services, the Get­System­Windows­Directory function retrieves the path of the system Windows directory, while the Get­Windows­Directory function retrieves the path of a Windows directory that is private for each user. On a single-user system, Get­System­Windows­Directory is the same as Get­Windows­Directory.

    What's going on here, and how do I test this scenario?

    When Terminal Services support was being added to Windows NT 4.0 in the mid 1990's, the Terminal Services team discovered that a lot of applications assumed that the computer was used by only one person, and that that person was a local administrator. This was the most common system configuration at the time, so a lot of applications simply assumed that it was the only system configuration.

    On the other hand, a Terminal Server machine can have a large number of users, including multiple users connected simultaneously, and if the Terminal Services team took no special action, you would have found that most applications didn't work. The situation "most applications didn't work" tends not to bode well for adoption of your technology.

    Their solution was to create a whole bunch of compatibility behaviors and disable them if the application says, "Hey, I understand that Terminal Server machines are different from your average consumer machine, and I know what I'm doing." One of those compatibility behaviors is to make the Get­Windows­Directory function return a private writable directory rather than the real Windows directory, because old applications assumed that the Windows directory was writable, and they often dumped their private configuration data there.

    The signal to disable compatibility behaviors is the IMAGE_DLLCHARACTER­ISTICS_TERMINAL_SERVER_AWARE flag in the image attributes of the primary executable. You tell the linker that you want this flag to be set by passing the /TSAWARE:YES parameter on the command line. (At some point, the Visual Studio folks made /TSAWARE:YES the default for all new projects, so you are probably getting this flag set on your files without even realizing it. You can force it off by going to Configuration Properties, and under Linker, then System, change the "Terminal Server" setting to "Not Terminal Server Aware".)

    Note that only the flag state on the primary executable has any effect. Setting the flag on a DLL has no effect. (This adds to the collection of flags that are meaningful only on the primary executable.)

    The other tricky part is that the Terminal Server compatibility behaviors kick in only on a Terminal Server machine. The way you create a Terminal Server machine has changed a lot over the years, as has the name of the feature.

    • In Windows NT 4.0, it was a special edition of Windows, known as Windows NT 4.0 Terminal Server Edition.
    • In Windows 2000, the feature changed its name from Terminal Server to Terminal Services and became an optional server component rather than a separate product. You add the component from Add/Remove Programs.
    • In Windows Server 2003 and Windows Server 2008, you go to the Configure Your Server Wizard and add the server rôle "Terminal Server."
    • In Windows Server 2008 R2, the feature changed its name again. The instructions are the same as in Windows Server 2008, but the rôle name changed to "Remote Desktop Services".
    • In Windows Server 2012, the feature retained its name but became grouped under the category "Virtual Desktop Infrastructure." This time, you have to enable the rôle server "Remote Desktop (RD) Session Host."

    Terminal Services is the Puff Daddy of Windows technologies. It changes its name every few years, and you wonder what it will come up with next.

  • The Old New Thing

    If the law says you can't file a petition, you might need to file it anyway, in case somebody later says that you should've even though the law says you couldn't

    • 9 Comments

    It sounds like a scene from the movie Brazil, but in fact it's the law.

    Let's rewind a bit. The introduction is a bit technical, but I'll try to keep it short.

    There is a legal filing known as a habeas petition and another known as a petition for review. There are rules regarding what each one covers and the deadlines for filing them. Prior to 2005, there was no deadline for habeas petitions, but you had to file your petition for review within 30 days of whatever it was the government did that you wanted to object to. In 2005, Congress passed (and the President signed) a law which recategorizes what the two types of filings covered, and many claims that had fallen under the habeas petition have been reclassified as requiring a petition for review instead.

    This change in the rules creates a gap in coverage because Congress forgot to include a grandfather clause (or, for computer geeks, a "smooth migration plan"): What if, at the time the new law took effect, the thing you want to complain about was reclassified as requiring a petition for review, but it took place more than 30 days ago? You wake up one morning and somebody tells you, "Hey, there's a new law today. You just lost your right to respond."

    What you do, then, is file a lawsuit challenging the new rules. And then two years later, the Third Circuit Court hears your case and rules that, yes, you're right, the law that Congress passed is unconstitutional (a violation of Section 9, Clause 2, known commonly as the Suspension Clause) because it denied you the opportunity to file a claim.

    And now here's the weird part.

    Instead of saying, "And therefore we strike down this part of the law as unconstitutional," the court says "And therefore we will retroactively rewrite the law so it is constitutional again (saving Congress and the President the trouble of having to do it themselves), and oh lookie here, according to this new law we just made up, you did have a constitutionally guaranteed opportunity to file your petition, but it expired two years ago."

    In other words, what you should have done in 2005 was hire a psychic, who would then instruct you to spend thousands of dollars hiring an attorney to draft and file a petition which, according to the law, you were legally barred from filing, in anticipation of the courts (two years later) rewriting the law in order to make that filing legal again. And then when you file your petition, you have to convince the court to accept it, explaining that yes, I know that I cannot legally file this petition, but a psychic told me to do it.

    You can read the court's decision yourself. (Despite the connotations associated with the term legalese, court decisions are actually quite readable. You just have to skip over the complicated footnotes.)

Page 368 of 453 (4,526 items) «366367368369370»