• The Old New Thing

    How many floppy disks did Windows 95 come on?

    • 36 Comments

    Thirteen.

    In case you were wondering.

    And those were thirteen of those special Distribution Media Format floppies, which are specially formatted to hold more data than a normal 1.44MB floppy disc. The high-capacity floppies reduced the floppy count by two, which resulted in a tremendous savings in cost of manufacturing and shipping.

    (I'm sure there are the conspiracy-minded folks who think that DMF was invented as an anti-piracy measure. It wasn't; it was a way to reduce the number of floppy disks. That the disks were difficult to copy was a side-effect, not a design goal.)

    (For comparison, Windows 3.1 came on six floppies. Windows NT 3.1 came on twenty-two. And yesterday, one of my colleagues reminded me that Windows NT setup asked for the floppy disks out of order! I guess it never occurred to them that they could renumber the disks.)

  • The Old New Thing

    Let's just make up some dollar values and print them as fact

    • 35 Comments

    Everybody is going nuts over a patent decision regarding the iPod interface, but that's not what I'm writing about (so don't ask me for my opinion). Rather, I'm reacting to the claims being made by many people that Apple will have to pay Microsoft $10 for every iPod.

    What I want to know is where this amount "$10" came from.

    Multiple people are confidently reporting a sawbuck as the amount in question. GeekCoffee attributes it to AppleInsider.com, but a search of AppleInsider turns up no article where they assigned a monetary value to the issue. A site called TrustedReviews repeats the $10 price tag with no source. ("You don't need a source. Just trust us!") MacNewsWorld even puts the amount in its headline, although the article gives no justification for how they arrived at it. Sky News helpfully converts the amount to £6 but again provides no source for this value.

    Are people just making up stuff and publishing it as fact? Or is there some root source for this $10 amount that I'm missing and which nobody is bothering to cite? (My suspicion is that one person took a wild guess and everybody else decided to run with it.)

  • The Old New Thing

    What are the access rights and privileges that control changing ownership of an object?

    • 11 Comments

    Changing the ownership of an object (typically a file) is not difficult in principle: You call the SetNamedSecurityInfo function with the new security descriptor.

    The hard part is getting to that point. (Thanks to John, a colleague in security, for correcting an earlier draft of this entry.)

    If you have WRITE_OWNER access on an object, then you can change the owner of the object to yourself (or to any SID in your token that has the SE_GROUP_OWNER attribute): you can take ownership. However, you cannot change the owner to somebody else: you cannot give ownership to another person. Doing that would allow you to violate quota restrictions.

    Imagine if this were possible, that you could change the ownership to something that you aren't a member of: Your account is at its disk quota. No problem, you just find somebody who isn't over quota (like Fred in Accounting) and take some of your biggest files and set their owner to Fred. This causes the disk space to be charged to its new owner Fred, without Fred even knowing that it has happened to him. If you put the file in a directory that Fred doesn't have access to, poor Fred will start getting "You are over disk quota" messages and have no way of finding this evil file that you charged to him. It's like stealing somebody's library card and checking out books with it.

    In order to set the owner to somebody else, you need to assert SeRestorePrivilege, which by default is assigned to administrators and backup operators. Backup operators need to be able to set the owner to somebody else because restoring its security descriptor is an important part of the process of restoring a file from backup.

    But what about SeTakeOwnershipPrivilege? That privilege is assigned to administrators, and it lets you act as if you had WRITE_OWNER access (but not SeRestorePrivilege) to everything. With SeTakeOwnershipPrivilege, you can take ownership of any file, but you can't assign it to somebody else.

    And then there's the mysterious CREATOR_OWNER SID, described in a Knowledge Base article as well as in a blog entry by Larry Osterman. The important thing to remember is that granting CREATOR_OWNER SID to an object after it has been created doesn't actually grant anything to the creator or owner. Read the linked articles for more details.

  • The Old New Thing

    What I'll be doing at this year's PDC

    • 6 Comments

    I will be heading down to Los Angeles the Friday before the PDC in order to visit friends and relatives and to check out the King Tut exhibit at the Los Angeles County Museum of Art. The last time Tutankhamun came to the United States was back in the late 1970's. I was an elementary school student and a few of my classmates were lucky enough to have obtained tickets to the exhibition; they gave it rave reviews.

    I will show up at the Convention Center when the PDC proper begins on Tuesday. I am officially scheduled to be in the Fundamentals Lounge from 11:30am to 2:30pm on Tuesday, then again on Thursday all day after my talk. Unofficially, I plan to be in the Fundamentals Lounge pretty much the entire time, though I may step out every so often to check out the exhibitors' booths and hands-on labs, to eat, or just to tease the people in the other lounges.

    What this means for you is that if you have something you want to discuss with me, you can just drop in the Fundamentals Lounge and there's a good chance I'll be there. No need to make an appointment. Don't be afraid to approach me; if I didn't want to be disturbed I'd have stayed in my hotel room! If I'm not around, you can call the main Microsoft switchboard +1-425-882-8080 and ask for me, and the call will be forwarded to my mobile.

    As for my talk, it will be in the style of a lecture, so there will be no slides. Slides will be provided in the handouts for completeness, but I won't use them. I'm told the talk will be recorded, and it is my understanding that the post-conference DVD will contain copies of every talk, so those of you who attend will be able to re-live the excitement in the comfort of your very own cubicle. (And to pre-empt the inevitable follow-up question: The PDC team own the recording of my talk, so don't ask me if I can make a copy available. It's not mine to give out.)

    One consequence of giving a lecture-style talk is that I will be using a Tablet PC as a sort of electronic chalkboard. There's one catch, though: I don't own a Tablet PC myself. I'll try to borrow one from a colleague for my talk, but in the worst-case scenario, I may get up on stage and ask to borrow one from an audience member. (Downside of loaning me your Tablet PC: You can't take notes on your Tablet PC during the talk. Upside: You get a copy of all the notes and diagrams!)

  • The Old New Thing

    Why is processor affinity inherited by child processes?

    • 23 Comments

    Consider why a typical program launches child processes. (Shell programs like Explorer aren't typical.) It's because the task at hand is being broken down into sub-tasks which for whatever reason has been placed into a child process. An Example of this would be, say, a multi-pass compiler/linker, where each pass is implemented as a separate process in a pipeline.

    Now consider why you might want to set a process's affinity mask to restrict it to a single processor. One reason is that the program may have bugs that cause it to crash or behave erratically on multi-processor machines. This was common for older programs that were written for uni-processor versions of Windows or when multi-processor machines were still prohibitively expensive. In this case, you would launch the program in a suspended state, by passing the CREATE_SUSPENDED flag to the CreateProcess function, then set the processor affinity mask for that process to a single processor, then resume the process's main thread.

    But what if the problem was in a child process of the process you're launching? Since you don't have control over how the process launches its child, you have no way to sneak in and set the child process's processor affinity mask. That's why the processor affinity mask is inherited: If you set it on the parent process, this covers all the child helper processes that process may launch as part of its execution.

    Another reason why you might want to set a process's affinity mask is to restrict its CPU usage. (For example, you might restrict a CPU-intensive application to a single processor of your dual-processor machine.) And again, if the process launches child processes, you want those child processes to be subject to the same restriction as their parent so that the task as a whole remains restricted to a single processor.

    That's why processor affinity is inherited by child processes. Because it's nearly always what you want.

  • The Old New Thing

    When people ask for security holes as features: Silent install of uncertified drivers

    • 79 Comments

    Probably the single greatest source of bluescreen crashes in Windows XP is buggy device drivers. Since drivers run in kernel mode, there is no higher authority checking what they're doing. If some user-mode code runs amok and corrupts memory, it's just corrupting its own memory. The process eventually crashes, but the system stays up. On the other hand, if a driver runs amok and corrupts memory, it's corrupting your system and eventually your machine dies.

    In acknowledgement of the importance of having high-quality drivers, Windows XP warns you when an uncertified driver is being installed. Which leads to today's topic, a question from a device driver author.

    When I try to install any driver, I get a User Consent Dialog box which tells the user that this is an unsigned driver. Is it possible to author a driver installation package that by-passes this user consent dialog box?

    The whole purpose of that dialog is to prevent the situation you desire from happening! [typo fixed 5pm] If you don't want the warning dialog, submit your driver for certification. (For testing purposes, you can sign your drivers with the test root certificate and install the test root certificate before running your setup program. Of course, installing the test root certificate also causes the desktop to read "For test purposes only" as a reminder that your machine is now allowing test-signed drivers to be installed.)

    Driver writers, of course, find the certification process cumbersome and will do whatever they can to avoid it. Because, of course, if you submit your driver for certification, it might fail! This has led to varying degrees of shenanigans to trick the WHQL team into certifying a driver different from the one you intend to use. My favorite stunt was related to my by a colleague who was installing a video card driver whose setup program displayed a dialog that read, roughly, "After clicking OK, do not touch your keyboard or mouse while we prepare your system." After you click OK, the setup program proceeds to move the mouse programmatically all over the screen, opening the Display control panel, clicking on the Advanced button, clicking through various other configuration dialogs, a flurry of activity for what seems like a half a minute. When faced with a setup program that does this, your natural reaction is to scream, "Aaaiiiiigh!"

  • The Old New Thing

    On being attacked by a sidewalk

    • 23 Comments

    Yesterday, I was attacked by a sidewalk.

    I was cycling from work to a friend's house for dinner and was northbound in the shoulder on 172nd Ave NE in Redmond. As I reached the intersection with NE 138th St., I was momentarily distracted, perhaps by my water bottle, I forget. This lapse of attention resulted in my failing to notice that north of NE 138th St., what used to be the shoulder becomes completely consumed by a sidewalk which leaps into the road out of nowhere.

    A sidewalk with a sharp curb.

    Fortunately, the curb curves into position, so instead of running headfirst into a curb, my wheels were merely nudged to the left about sixty centimeters. Still, it was more than enough to throw me flying off the seat onto the ground at around 30kph. Luckily, my rear end took the brunt of the impact, with minor scraping on my right leg and right arm.

    I'm writing this to serve as a warning to anybody who cycles along 172nd Ave NE: There a sidewalk lying in wait at NE 138th St.

    (After dinner, we watched the most recent episode of Battlestar Galactica then camped in the backyard to observe the Perseid meteor shower. I spotted only three meteors. I'm not a very good meteor-spotter—I glimpsed only three—what with my smudgy glasses and poor night vision.)

  • The Old New Thing

    The poor man's way of identifying memory leaks

    • 17 Comments

    There is a variety of tools available for identifying resource leaks, but there's one method that requires no tools or special compiler switches or support libraries: Just let the leak continue until the source becomes blatantly obvious.

    Nightly automated stress testing is a regular part of any project. Some teams use screen savers as the trigger, others use a custom program, still others require manual launching of the stress test, but by whatever means, after you've gone home for the day, your computer connects to a central server and receives a set of tests that it runs all night.

    One of the things that these overnight tests often turn up are memory leaks of one sort or another, identified by the stress team because your program's resource usage has gone abnormally high. But how do you debug these failures? These machines aren't running a special instrumented build with your leak detection tool, so you can't use that.

    Instead, you use the "target-rich environment" principle.

    Suppose you're leaking memory. After fifteen hours of continuous heavy usage, your program starts getting out-of-memory failures. You're obviously leaking something, but what?

    Think about it: If you are leaking something, then there are going to be a lot of them. Whereas things you aren't leaking will be few in number. Therefore, if you grab something at random, it will most likely be a leaked object! In mathematical terms, suppose your program's normal memory usage is 15 megabytes, but for some reason you've used up 1693 megabytes of dynamically-allocated memory. Since only 15 megabytes of that is normal memory usage, the other 1678 megabytes must be the leaked data. If you dump a random address from the heap, you have a greater-than-99% chance of dumping a leaked object.

    So grab a dozen or so addresses at random and dump them. Odds are you'll see the same data pattern over and over again. That's your leak. If it's a C++ object with virtual methods, dumping the vtable will quickly identify what type of object it is. If it's a POD type, you can usually identify what it is by looking for string buffers or pointers to other data.

    Your mileage may vary, but I've found it to be an enormously successful technique. Think of it as applied psychic powers.

  • The Old New Thing

    Adding a lookup control to the dictionary: Searching Pinyin

    • 4 Comments

    Finally we start searching. For now, the search algorithm is going to be very simple: The string you type into the edit control will be treated as the start of a Pinyin word or phrase. We'll make it fancier later.

    Here is where a lot of the groundwork (some of which I called out explicitly and some of which I slipped in without calling attention to it) starts to pay off.

    Up until now, the items in the listview came directly from the dictionary. Of course, when a word is being looked up, we want to reduce the list to those that match the word or phrase being searched for. We will introduce a new member m_vMatch which is a vector of pointers to the items we actually want to display.

    class RootWindow : public Window
    {
     ...
     // const DictionaryEntry& Item(int i) { return m_dict.Item(i); }
     // int Length() { return m_dict.Length(); }
     const DictionaryEntry& Item(int i) { return *m_vMatch[i]; }
     int Length() { return m_vMatch.size(); }
     ...
     void OnCommand(UINT id, UINT cmd);
     void Refilter();
     ...
    private:
     ...
     vector<const DictionaryEntry*> m_vMatch;
    };
    

    By tweaking our Item and Length member functions, we can now render out of the list of matches instead of out of the entire dictionary.

    LRESULT RootWindow::OnCreate()
    {
     ...
     // ListView_SetItemCount(m_hwndLV, Length());
     ...
     m_hwndLastFocus = m_hwndEdit;
     m_vMatch.reserve(m_dict.Length());
     Refilter();
    
     return 0;
    }
    

    Since the list of matches is at most the number of words in the dictionary, we can reserve that size up front and avoid needless reallocations. Once we've done that, we call our new Refilter method to compute the matches (which populates the listview). It is Refilter that will do the ListView_SetItemCount, so there's no point in us doing it here.

    void RootWindow::OnCommand(UINT id, UINT cmd)
    {
     switch (id) {
     case IDC_EDIT:
      switch (cmd) {
      case EN_CHANGE:
       Refilter();
      }
      break;
     }
    }
    
      // add to RootWindow::HandleMessage()
      case WM_COMMAND:
       OnCommand(GET_WM_COMMAND_ID(wParam, lParam),
                 GET_WM_COMMAND_CMD(wParam, lParam));
       break;
    

    We also rebuild the list of matches if the user makes a change to the edit control. This means that there is no need for a "Search" button. The listview auto-filters as you type.

    void RootWindow::Refilter()
    {
     WCHAR szBuf[256];
     DWORD cchBuf = GetWindowText(m_hwndEdit, szBuf, 256);
     m_vMatch.clear();
     for (int i = 0; i < m_dict.Length(); i++) {
      const DictionaryEntry& de = m_dict.Item(i);
      if (StrCmpNIW(de.m_pszPinyin, szBuf, cchBuf) == 0) {
       m_vMatch.push_back(&de);
      }
     }
     ListView_SetItemCount(m_hwndLV, Length());
     ListView_SetItemState(m_hwndLV, -1, 0, LVIS_SELECTED);
     InvalidateRect(m_hwndLV, NULL, FALSE);
    }
    

    Building the list of matches is rather simple and anticlimactic. We get the string the user typed into the edit control and walk through all the words in the dictionary, seeing if the Pinyin begins with the user's typing. If so, then we add it to the match vector.

    Once the match list is built up, we tell the listview how many we found, clear the selection (so that the selection doesn't appear to move around from one word to another as items are filtered in or out), and invalidate the client rectangle to trigger a repaint.

    That's all there is to it. If you run this program and start typing into the edit control, you'll see the list of words in the listview grow and shrink as you type.

    That's all for this month. Next month, we'll work on expanding the scope of the search.

  • The Old New Thing

    Whatever you do, don't ask for coffee

    • 9 Comments

    Heather Hamilton makes an odd discovery on her flight to Seattle.

Page 354 of 439 (4,383 items) «352353354355356»