• The Old New Thing

    Enumerating integer compositions (the return of the binomial coefficients)

    • 12 Comments
    In number theory, a composition of an integer is an ordered sequence of positive integers which sum to the target value. For example, the value 3 can be written as 3, 1+2, 2+1, or 1+1+1.

    You can think about the target number as a string of stars, and a composition is a way of breaking the stars into groups. For example, here are the compositions of 3:

    * * *3
    *|* *1+2
    * *|*2+1
    *|*|*  1+1+1

    How would you generate all compositions of a particular length? In the above example, the compositions of length 2 would be 1+2 and 2+1. Let's take a look at the last star in the composition. If it is immediately preceded by a space, then removing it results in a string one star shorter, but with the same number of groups (but the last group is one star smaller). In other words, what's left behind is a composition of n − 1 of length k. You can recover the original string by adding a star at the end.

    On the other hand, if the last star is immediately preceded by a vertical line, then removing it deletes an entire group, so what remains is a string one star shorter with one fewer group. In other words, what's left behind is a composition of n − 1 of length k − 1. You can recover the original string by adding a separator and a star at the end.

    Therefore, our algorithm goes like this:

    • Handle base cases.
    • Otherwise,
      • Recursively call Compositions(n − 1, k) and add a star to the end. (I.e., increment the last term.)
      • Recursively call Compositions(n − 1, k − 1) and add a vertical line and a star to the end. (I.e., add a +1 to the end.)
    function Compositions(n, k, f) {
     if (n == 0) { return; }
     if (k == 1) { f([n]); return; }
     Compositions(n-1, k, function(s) {
      f(s.map(function(v, i) { // increment the last element
        return i == s.length - 1 ? v + 1 : v;
      }));
     });
     Compositions(n-1, k-1, function(s) {
      f(s.concat(1)); // append a 1
     });
    }
    
    Compositions(5, 3, function(s) { console.log(s.join("+")); });
    

    Once again, this algorithm should look awfully familiar, because we've seen it twice before, once in the context of enumerating subsets with binomial coefficients, and again when Enumerating bit strings with a specific number of bits set. All we're doing is decorating the results differently.

    Here's a way to see directly how compositions are the same as subset selection. Let's ignore the stars and instead look at the gaps between them.

    * * * * *
     ^ ^ ^ ^
    

    Each of the gaps can hold either a space or a vertical line. Breaking n into k pieces is the same as drawing k − 1 vertical lines in the n − 1 gaps. In other words, you have n − 1 locations and you want to choose k − 1 of them: Ta da, we converted the problem into generating subsets of size k − 1 from a collection of size n − 1. (In mathematics, this visualization is known as stars and bars.)

    Therefore, we could have made the Subsets function do the work:

    function Compositions(n, k, f) {
     Subsets(n-1, k-1, function(s) {
      s.push(n);
      f(s.map(function(v, i) { return v - (s[i-1]||0); }));
      s.pop();
     });
    }
    

    The callback merely calculates the differences between adjacent elements of the subset, which is the number of stars between each line. There is a little extra playing around in order to create a virtual vertical bar at the beginning and end.

    Since there is an incremental way of enumerating subsets, there should be an incremental way of enumerating compositions. If you look at how the incremental subset enumerator works, you can see how it maps to incremental composition enumeration: Incrementing an index is the same as moving a bar to the right, which maps to incrementing one term and decrementing the subsequent term. Resetting subsequent indices to the minimum values corresponds to setting the corresponding term to 1. The only trick is maintaining the value of the final term, which gathers all the values squeezed out of earlier terms.

    function NextComposition(s) {
     var k = s.length;
     for (var i = k - 1; i >= 1; i--) {
      if (s[i] > 1) {
       s[i]--;
       s[i-1]++;
       for (; i < k - 1; i++) { s[k-1] += s[i] - 1; s[i] = 1; }
       return true;
      }
     }
     return false;
    }
    

    Exercise: If you wanted to generate all compositions of any length, you could do it by generating all compositions of length 1, then compositions of length 2, and so on up to length n. What's the easier way of doing it?

    Bonus chatter: If you want to generate all partitions (which is like compositions, except that order doesn't matter), you can use this recursive version or this iterative one.

  • The Old New Thing

    If I duplicate a handle, can I keep using the duplicate after closing the original?

    • 10 Comments

    A customer asked whether it was okay to use a duplicated handle even after the original handle was closed.

    Yes. That's sort of why you would duplicate it.

    Duplicating a handle creates a second handle which refers to the same underlying object as the original. Once that's done, the two handles are completely equivalent. There's no way to know which was the original and which is the duplicate. Either handle can be used to access the underlying object, and the underlying object is not torn down until all handles to it have been closed.

    One tricky bit here is that since you have two ways to refer to the same thing, changes made to the object via one handle will be reflected when observed through the other handle. That's because the changes you're making are to the object itself, not to the handle. For example, if you duplicate the handle to an event, then you can set the event via either handle.

    That may all sound obvious, but one thing to watch out for is the case of file handles: The current file position is a property of the file object, not the handle. Say you duplicate a file handle and give the original to one component and the duplicate to another. Now, when either component reads from or writes to the file, it's going to change the current position of the file object, and consequently may confuse the other component (who may not have expected the current position to be changing). Also, if the underlying file is a synchronous file handle, the file operations on the underlying file will be synchronized. If one component starts a read, the other component won't be able to access the file object until that read completes.

    If you want to create a second handle to a file that has its own file pointer and is not synchronized against the first file handle, you can use the Re­Open­File function to create a second file object with its own synchronization and its own file position, but which refers to the same underlying file.

    (Don't forget to get your sharing modes right! The second file object's access and sharing modes must be compatible with access and sharing modes of the original file object. Otherwise the call will fail with a sharing violation.)

  • The Old New Thing

    Using the REFIID/void** pattern for returning COM objects for future-proofing and to avoid problems with dependencies

    • 36 Comments

    Suppose you have a function that creates a reference to a COM object:

    // pixie.h
    
    STDAPI CreateShellItemFromPixieDust(
        const PIXIEDUST *ppd,
        IShellItem **ppsi);
    

    There are a few issues with this design.

    First of all, it requires that whoever uses your header file must have included shlobj.h first, since that's where IShell­Item is defined. You could solve that problem by putting #include <shlobj.h> at the top of pixie.h, but that creates its own problems. For example, many header files alter their behavior based on symbols that have been #defined, and including that other header file as part of pixie.h means that it's going to use the settings that were active at the time pixie.h was included (which may not be what the clients of your header file are expecting). For example:

    #include <windows.h>
    #include <ole2.h>
    #include <pixie.h>
    #define STRICT_TYPED_ITEMIDS
    #include <shlobj.h>
    

    This program wants to use strict typed item IDs, so it defines the magic symbol before including shlobj.h. Unfortunately, that request is ignored because the pixie.h header file secretly included shlobj.h prematurely.

    This can get particularly messy if somebody wants to include shlobj.h with particular preprocessor tricks temporarily active.

    #include <windows.h>
    #include <ole2.h>
    #include <pixie.h>
    
    // The WINDOWDATA structure added in Windows Vista conflicts
    // with the one we defined back in 2000, so rename it to
    // WINDOWDATA_WINDOWS.
    #define WINDOWDATA WINDOWDATA_WINDOWS
    #include <shlobj.h>
    #undef WINDOWDATA
    
    // Here's our version of WINDOWDATA
    #include <contosotypes.h>
    

    This code works around a naming conflict that was created when Windows Vista added a structure called WINDOW­DATA to shlobj.h. The application already had a structure with the same name, so it has to rename the one in shlobj.h to some other name to avoid a redefinition error.

    If you made pixie.h include shlobj.h on its own, it would do so without this fancy renaming, and the developers of that code will curse and say something like this:

    #include <windows.h>
    #include <ole2.h>
    
    // The WINDOWDATA structure added in Windows Vista conflicts
    // with the one we defined back in 2000, so rename it to
    // WINDOWDATA_WINDOWS.
    #define WINDOWDATA WINDOWDATA_WINDOWS
    
    // pixie.h secretly includes shlobj.h so we have to put its #include
    // under WINDOWDATA protection.
    #include <pixie.h>
    
    #include <shlobj.h>
    
    #undef WINDOWDATA
    
    
    // Here's our version of WINDOWDATA
    #include <contosotypes.h>
    

    Another problem with the Create­Shell­Item­From­Pixie­Dust function is that it hard-codes the output interface to IShell­Item. When everybody moves on to IShell­Item2, all the callers will have to follow the Create­Shell­Item­From­Pixie­Dust call with a Query­Interface to get the interface they really want. (Which, if your object is out-of-process, could mean another round trip to the server.)

    The solution to both of these problems is to simply make the caller specify what type of object they want.

    // pixie.h
    
    STDAPI CreateShellItemFromPixieDust(
        const PIXIEDUST *ppd,
        REFIID riid,
        void **ppv);
    

    Now that we are no longer mentioning IShell­Item explicitly, we don't need to include shlobj.h any more. And if the caller wants IShell­Item2, they can just ask for it.

    Your creation function used to look like this:

    STDAPI CreateShellItemFromPixieDust(
        const PIXIEDUST *ppd,
        IShellItem **ppsi)
    {
        *ppsi = nullptr;
        IShellItem *psiResult;
        HRESULT hr = ... do whatever ...;
        if (SUCCEEDED(hr))
        {
           *ppsi = psiResult;
        }
        return hr;
    }
    

    You simply have to tweak the way you return the pointer:

    STDAPI CreateShellItemFromPixieDust(
        const PIXIEDUST *ppd,
        REFIID riid,
        void **ppv)
    {
        *ppsi = nullptr;
        IShellItem *psiResult;
        HRESULT hr = ... do whatever ...;
        if (SUCCEEDED(hr))
        {
           hr = psiResult->QueryInterface(riid, ppv);
           psiResult->Release();
        }
        return hr;
    }
    

    Callers of your function would go from

    IShellItem *psi;
    hr = CreateShellItemFromPixieDust(ppd, &psi);
    

    to

    IShellItem *psi;
    hr = CreateShellItemFromPixieDust(ppd, IID_PPV_ARGS(&psi));
    

    If the caller decides that they really want an IShell­Item2, they merely have to change their variable declaration; the call to the creation function is unchanged.

    IShellItem2 *psi;
    hr = CreateShellItemFromPixieDust(ppd, IID_PPV_ARGS(&psi));
    
  • The Old New Thing

    Why are only some of the Windows 7 system notification icons colorless?

    • 52 Comments

    André decided to play "gotcha" by noting that not all of the notification icons went colorless and wondered what the criteria was for deciding which ones to make colorless and which ones to make colorful.

    It's very simple: The design team generated colorless versions of the most commonly-seen notification icons. They didn't have the time to generate colorless versions of all notification icons, so they focused on the ones that gave them the most benefit.

    This is the standard tradeoff you have to make whenever you have finite resources. Eventually the marginal benefit of redrawing one more icon exceeds its marginal cost, at which point you stop. The marginal cost is measured not only in actual resources (designers can redraw only so many icons per day, and you have money to hire only so many designers) but also in opportunity cost (time spent redrawing icons to be colorless is time not spent on other design tasks).

    This is the same reason that not all icons in Windows XP were given the full-color perspective-view treatment. For example, nearly all of the icons in the Administrative Tools section are the old Windows 2000-style 16-color flat (or isometric) icons. The design team focused on the 100ish most commonly used icons and went to the effort of redrawing them in the Windows XP style. The more rarely-used icons were left in the old style because the cost of converting them did not merit the benefit.

    The same thing happened in Windows Vista, when the icon design changed yet again. The style became less stylized and more realistic, but not quite photorealistic, and the angle of presentation changed. The design team had the resources to convert the most commonly used icons, and the rest were left as they were.

    It's the Pareto Principle again. If you have finite resources (and who doesn't) you may find that you can get 80% of the benefit by doing only 20% of the work. And that leaves 80% of your capacity available to address some other problem.

  • The Old New Thing

    How do I turn off email reminders for my Windows Live calendar, and disable the birthday calendar while I'm at it?

    • 12 Comments

    While having lunch with my colleagues a few days ago, they complained that they get annoying email for all their calendar events.

    I mentioned, "So turn off the email notifications."

    "You can do that?" they replied, incredulous.

    Here's how you do it.

    First, go to calendar.live.com and sign in to your calendar.

    In the upper right corner of the screen, click on the gear icon.

    Sven Svensson
    👨

    From the drop-down menu, select Options. From the Options page, select the calendar you want to change.

    Edit your reminder and calendar settings
      Sven's calendar
      Birthday calendar

    In the Calendar settings, untick the checkboxes.

    Notifications
    Email notifications
    Get reminders for events and tasks
    Get daily agenda

    And then click Save to save your changes.

    My colleagues also noted "It used to mean something when somebody remembered your birthday. But now, everybody gets a notification on your birthday, and you get birthday wishes from random people you haven't talked to in years." Which led to the next complaint, "I just want to turn off the birthday calendar."

    No problem. Go back and click on the gear icon, and instead of selecting Options, look under Filter Calendars and untick the check box next to Birthday calendar.

    If you have a Windows Phone, you can remove it from your phone calendar by opening the Calendar app, opening the appbar, selecting settings, and then unticking the check box next to Birthday calendar.

  • The Old New Thing

    Customing the standard color-picker dialog

    • 11 Comments

    Today's Little Program does a little bit of customization of the Choose­Color dialog. We do this by, um, doing what the documentation says.

    For the color dialog, we take the template in color.dlg and modify it. Just to get our feet wet, we won't customize anything at all! This ensures that we have the basics down before we start trying anything fancy.

    Handy tip: Before trying to customize something, first write code that does it uncustomized. That way, you have a known working starting point.

    #include <windows.h>
    
    #include <colordlg.h>
    
    1 DIALOG LOADONCALL MOVEABLE DISCARDABLE 2, 0, 298, 184
    STYLE WS_BORDER | DS_MODALFRAME | WS_CAPTION | WS_POPUP | WS_SYSMENU |
          DS_3DLOOK
    CAPTION "Color"
    FONT 8 "MS Shell Dlg"
    BEGIN
        LTEXT           "&Basic colors:", -1, 4, 4, 140, 9
        CONTROL         "", COLOR_BOX1, "static",
                        SS_SIMPLE | WS_CHILD | WS_TABSTOP | WS_GROUP,
                        4, 14, 140, 86
    
        LTEXT           "&Custom colors:", -1, 4, 106, 140, 9
        CONTROL         "",  COLOR_CUSTOM1, "static",
                        SS_SIMPLE | WS_CHILD | WS_TABSTOP | WS_GROUP,
                        4, 116, 140, 28
    
        PUSHBUTTON      "&Define Custom Colors >>" COLOR_MIX, 4, 150, 138, 14,
                        WS_TABSTOP | WS_GROUP
    
        DEFPUSHBUTTON   "OK", IDOK, 4, 166, 44, 14, WS_GROUP | WS_TABSTOP
        PUSHBUTTON      "Cancel", IDCANCEL, 52, 166, 44, 14, WS_GROUP | WS_TABSTOP
        PUSHBUTTON      "&Help", pshHelp, 100, 166, 44, 14, WS_GROUP | WS_TABSTOP
    
        CONTROL         "", COLOR_RAINBOW, "static",
                        SS_SUNKEN | SS_SIMPLE | WS_CHILD, 152, 4, 118, 116
    
        CONTROL         "", COLOR_LUMSCROLL, "static",
                        SS_SUNKEN | SS_SIMPLE | WS_CHILD, 280, 4, 8, 116
    
        CONTROL         "", COLOR_CURRENT, "static",
                        SS_SUNKEN | SS_SIMPLE | WS_CHILD, 152, 124, 40, 26
    
        PUSHBUTTON      "&o", COLOR_SOLID, 300, 200, 4, 14, WS_GROUP
        RTEXT           "Color", COLOR_SOLID_LEFT, 152, 151, 20, 9
        LTEXT           "|S&olid", COLOR_SOLID_RIGHT, 172, 151, 20, 9
    
        RTEXT           "Hu&e:", COLOR_HUEACCEL, 194, 126, 20, 9
        EDITTEXT,       COLOR_HUE, 216, 124, 18, 12, WS_GROUP | WS_TABSTOP
    
        RTEXT           "&Sat:", COLOR_SATACCEL, 194, 140, 20, 9
        EDITTEXT,       COLOR_SAT, 216, 138, 18, 12, WS_GROUP | WS_TABSTOP
    
        RTEXT           "&amp;Lum:", COLOR_LUMACCEL, 194, 154, 20, 9
        EDITTEXT,       COLOR_LUM, 216, 152, 18, 12, WS_GROUP | WS_TABSTOP
    
        RTEXT           "&Red:", COLOR_REDACCEL, 243, 126, 24, 9
        EDITTEXT,       COLOR_RED, 269, 124, 18, 12, WS_GROUP | WS_TABSTOP
    
        RTEXT           "&Green:", COLOR_GREENACCEL, 243, 140, 24, 9
        EDITTEXT,       COLOR_GREEN, 269, 138, 18, 12, WS_GROUP | WS_TABSTOP
    
        RTEXT           "Bl&ue:", COLOR_BLUEACCEL, 243, 154, 24, 9
        EDITTEXT,       COLOR_BLUE, 269, 152, 18, 12, WS_GROUP | WS_TABSTOP
    
        PUSHBUTTON      "&Add to Custom Colors", COLOR_ADD, 152, 166, 142, 14,
                        WS_GROUP | WS_TABSTOP
    END
    

    Our resource file is just a copy of the original color.dlg file with no customizations. We stick a windows.h in front, and assign it a custom resource ID of 1. Let's see if we can display it.

    #define UNICODE
    #define _UNICODE
    #define STRICT
    #include <windows.h>
    #include <commdlg.h>
    
    int WINAPI wWinMain(
        HINSTANCE hinst, HINSTANCE hinstPrev,
        LPWSTR lpCmdLine, int nCmdShow)
    {
     COLORREF rgCustColors[16] = { 0 };
     CHOOSECOLOR cc = { sizeof(cc) };
     cc.hInstance = reinterpret_cast<HWND>(hinst);
     cc.lpTemplateName = MAKEINTRESOURCE(1);
     cc.Flags = CC_ENABLETEMPLATE;
     cc.lpCustColors = rgCustColors;
     if (ChooseColor(&cc)) {
      MessageBox(nullptr, TEXT("Thank you"), TEXT("Sample"), MB_OK);
     }
     return 0;
    }
    

    The hInstance member of the CHOOSE­COLOR structure is incorrectly declared as HWND, so we need to stick in a cast to keep everybody happy.

    Run this program, and... everything looks perfectly normal. Good! Now we can customize it.

    First, let's just add a message to the dialog.

    1 DIALOG LOADONCALL MOVEABLE DISCARDABLE 2, 0, 298, 198
    ...
    
        LTEXT           "Don't forget to smile!",
                        -1, 4, 166, 138, 14
    
        DEFPUSHBUTTON   "OK", IDOK, 4, 180, 44, 14, WS_GROUP | WS_TABSTOP
        PUSHBUTTON      "Cancel", IDCANCEL, 52, 180, 44, 14, WS_GROUP | WS_TABSTOP
        PUSHBUTTON      "&Help", pshHelp, 100, 180, 44, 14, WS_GROUP | WS_TABSTOP
    ...
    

    Rebuild the program and run it. Hey look, a happy message! Note that in order to fit the message in the dialog box, we had to make the dialog box taller and move some buttons out of the way.

    Just adding static text is nice, but it's not particularly interesting. So let's add a check box to the dialog too.

        AUTOCHECKBOX    "I remembered to s&mile",
                        1000, 4, 166, 138, 14, WS_TABSTOP
    

    In addition to remembering the color the user chose, we also want to remember whether they checked the box that says that they smiled. The documentation says that when the hook procedure receives a WM_INIT­DIALOG, the lParam points to the CHOOSE­COLOR dialog. We therefore have two options for passing extra data to the hook procedure.

    I'll use the traditional method for now. The lCust­Data is a pointer to a BOOL that receives the checkbox state on exit.

    UINT_PTR CALLBACK CCHookProc(
        HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
      switch (uMsg)
      {
      case WM_INITDIALOG:
        {
          auto pcc = reinterpret_cast<CHOOSECOLOR*>(lParam);
          auto pfSmiled = reinterpret_cast<BOOL*>(pcc->lCustData);
          SetProp(hdlg, TEXT("SmileResult"), pfSmiled);
        }
        break;
    
      case WM_DESTROY:
        {
          auto pfSmiled = reinterpret_cast<BOOL*>(
               GetProp(hdlg, TEXT("SmileResult")));
          if (pfSmiled) {
           *pfSmiled = IsDlgButtonChecked(hdlg, 1000);
          }
          RemoveProp(hdlg, TEXT("SmileResult"));
        }
      }
      return 0;
    }
    
    int WINAPI wWinMain(
        HINSTANCE hinst, HINSTANCE hinstPrev,
        LPWSTR lpCmdLine, int nCmdShow)
    {
     COLORREF rgCustColors[16] = { 0 };
     BOOL fSmiled = FALSE;
     CHOOSECOLOR cc = { sizeof(cc) };
     cc.hInstance = reinterpret_cast<HWND>(hinst);
     cc.lpTemplateName = MAKEINTRESOURCE(1);
     cc.Flags = CC_ENABLETEMPLATE  | CC_ENABLEHOOK;
     cc.lpCustColors = rgCustColors;
     cc.lCustData = reinterpret_cast<LPARAM>(&fSmiled);
     cc.lpfnHook = CCHookProc;
     if (ChooseColor(&cc) && !fSmiled) {
      MessageBox(nullptr, TEXT("You forgot to smile."),
                 TEXT("Sample"), MB_OK);
     }
     return 0;
    }
    

    Now, the program displays a message if you selected a color but did not check the I remembered to smile box.

  • The Old New Thing

    Communication between moving vehicles during the narrow window of the late 1990s

    • 39 Comments

    The long holiday weekend in the United States means that there are probably going to be a lot of people on road trips.

    Back in the old days before mobile phones, if you had multiple cars traveling together on a long trip, you had to stay within visible range of each other so that you didn't get separated. And if the car at the end of the convoy needed to pull over to take a bathroom break or something, they needed to rush to the front of the group and pantomime through the window to the passengers in the lead car to tell them what they were going to do, and then everybody would pull over together.

    I still remember those days.

    Of course, nowadays, you'd just whip out your mobile phone and call the other people in the group. "Hey, we need to stop for a bathroom break. You can join us, or we'll just catch up with you down the road."

    There was a narrow window of a few years where WiFi hardware was generally available, if somewhat expensive (in the form of a PCMCIA PC Card for your laptop and a $1000 base station)¹ and mobile phone coverage along highways in less populated areas was spotty or nonexistent. That was the window of time during which I wrote a chat program for multi-car road trips.

    The idea was that we would establish an ad-hoc wireless network among the laptops, and the program would act as a peer-to-peer instant messaging program. We would be the world's fastest-moving WiFi hotspot. As long as the cars stayed within around 100 meters of each other, we would (presumably) still have connectivity. The program was robust to outages, and it could handle devices dynamically coming into or leaving communication range.

    With this technological contraption, we didn't have to make everybody stop and pull over in order to decide where to have lunch. We could just start an IM conversation and work it out while still moving. (But if we wanted to take a bathroom break, everybody had to stop; otherwise the cars would get out of range.)

    I over-engineered this program, designing it to handle chats that if printed out would require a roll of paper over 300 kilometers long. In other words, for a 300km trip, you would have to be sending instant messages fast enough that you could drive on the paper coming out of the printer. (Related.) Another way of doing the math was observing that the program could in theory handle a cross-country trip where people were sending 500 messages per second the entire time. (Well, except it would have run out of memory long before hitting its design limits.)

    This program met an even sadder fate than my in-car mp3 player. At least I got to use that program a few times. Mobile phone technology quickly improved to the point where the car chat program was no longer necessary. It was never used at all!

    ¹ I still have my $1000 base station packed in a box somewhere. I wouldn't be surprised if my my mobile phone now has a faster data plan than that thing.

  • The Old New Thing

    It rather involved being on the other side of this airtight hatchway: Surreptitious file access by administrator

    • 43 Comments

    A security report was received that went something like this:

    A user can bypass file sharing locks by opening a read-only handle to the physical volume containing the file in question. This allows the user to extract the contents of protected files by reading the corresponding sectors directly from the disk. Since this operation requires administrator access, any user with administrator access can extract data from files that are normally inaccessible due to file locks, such as the SAM database.

    Yes, that's right. An attacker who gains administrator privileges can extract data from any file on the computer.

    But so what? The attacker is already on the other side of the airtight hatchway. They already pwn your machine. That a pwned machine can be pwned is not really all that surprising.

    That some files are not accessible due to file locks is not a security measure. It is a consequence of, um, file access.

    Besides, once you gain administrator access, a much easier way to steal the SAM is to merely grab a backup copy.

    What, you can't find a backup copy?

    No problem.

    After all, you're the administrator. One of your job responsibilities is to maintain regular system backups.

    So create a backup of the SAM file. Of course the system will let you do this. It is your job after all.

    For example, you can use the Volume Shadow Service to create a volume snapshot, then mount the snapshot and extract the SAM file.

    Bingo, instant copy of the SAM database.

    Just doing your job.

  • The Old New Thing

    Redirecting the Favorites folder is technically legal, but you wouldn't like it

    • 47 Comments

    A customer liaison asked for assistance in debugging why Internet Explorer frequently stops responding at their customer's site. "We have tried a number of things like clearning the temporary Internet files, disabling add-ons, and resetting Internet Explorer settings. Please let me know if you can provide guidance based on the dump files provided below to indicate what could be causing Internet Explorer to hang here."

    The dump file showed 23 threads, and all of them seemed to be normal, except for one which looked like this:

    ntdll!KiFastSystemCallRet
    ntdll!ZwOpenFile+0xc
    kernel32!BaseDllOpenIniFileOnDisk+0x1ec
    kernel32!BaseDllReadWriteIniFileOnDisk+0x22
    kernel32!BaseDllReadWriteIniFile+0x154
    kernel32!GetPrivateProfileStringW+0x35
    kernel32!GetPrivateProfileSectionNamesW+0x18
    shell32!CPrivateProfile::_GetPrivateProfileAlloc+0x9e
    shell32!CPrivateProfile::GetSectionNames+0xa0
    ieframe!CINIPropSetStg::Load+0x74
    ieframe!CInternetShortcutPropertyStore::_CreateStoreFromFile+0x4e
    ieframe!CInternetShortcutPropertyStore::Load+0x22
    ieframe!CInternetShortcut::LoadFromFileW+0x39
    ieframe!CInternetShortcut::Initialize+0x17
    shell32!InitializeFileHandlerWithFile+0x2d
    shell32!CFileSysItemString::HandlerCreateInstance+0x29a
    shell32!CFileSysItemString::LoadHandler+0x91
    shell32!CFSFolder::_CreatePerInstanceDefExtIcon+0x7d
    shell32!CFSFolder::_CreateDefExtIcon+0xe9
    shell32!CFSFolder::s_GetExtractIcon+0x1b
    shell32!CFSFolder::_BindHandler+0x209
    shell32!CFSFolder::GetUIObjectOf+0x21
    shell32!GetExtractIconW+0x31
    shell32!_GetILIndexFromItem+0x52
    shell32!SHMapPIDLToSystemImageListIndex+0x37
    ieframe!OrderItem_GetSystemImageListIndex+0x187
    ieframe!CSFToolbar::_GetBitmap+0x2f
    ieframe!CSFToolbar::_OnGetDispInfo+0x34
    ieframe!CSFToolbar::_OnNotify+0x8e
    ieframe!CISFBand::_OnNotify+0x2c
    ieframe!CSFToolbar::OnWinEvent+0x89
    ieframe!_FwdWinEvent+0x1d
    ieframe!CBandSite::_SendToToolband+0x44
    ieframe!CInternetToolbar::_OnNotify+0x2e
    ieframe!CInternetToolbar::SizableWndProc+0x223
    user32!InternalCallWinProc+0x23
    user32!UserCallWinProcCheckWow+0x14b
    user32!SendMessageWorker+0x4b7
    user32!SendMessageW+0x7c
    comctl32!CCSendNotify+0xbfb
    comctl32!SendNotifyEx+0x63
    comctl32!CReBar::_WndProc+0x24f
    comctl32!CReBar::s_WndProc+0x2c
    user32!InternalCallWinProc+0x23
    user32!UserCallWinProcCheckWow+0x14b
    user32!CallWindowProcAorW+0x97
    user32!CallWindowProcW+0x1b
    comctl32!CallOriginalWndProc+0x1a
    comctl32!CallNextSubclassProc+0x3d
    comctl32!DefSubclassProc+0x46
    ieframe!CInternetToolbar::CITBandSite::s_RebarSubclassWndProc+0x5a
    comctl32!CallNextSubclassProc+0x3d
    comctl32!MasterSubclassProc+0x54
    user32!InternalCallWinProc+0x23
    user32!UserCallWinProcCheckWow+0x14b
    user32!SendMessageWorker+0x4b7
    user32!SendMessageW+0x7c
    comctl32!CCSendNotify+0xbfb
    comctl32!CToolbar::TBGetItem+0x2c
    comctl32!CToolbar::DrawButton+0x5e9
    comctl32!CToolbar::DrawToolbarH+0x1ad
    comctl32!CToolbar::TBPaintImpl+0xd5
    comctl32!CToolbar::TBPaint+0x18c
    comctl32!CToolbar::ToolbarWndProc+0xd2e
    comctl32!CToolbar::s_ToolbarWndProc+0x9b
    user32!InternalCallWinProc+0x23
    user32!UserCallWinProcCheckWow+0x14b
    user32!CallWindowProcAorW+0x97
    user32!CallWindowProcW+0x1b
    comctl32!CallOriginalWndProc+0x1a
    comctl32!CallNextSubclassProc+0x3d
    comctl32!DefSubclassProc+0x46
    ieframe!CSFToolbar::_DefWindowProc+0xb8
    ieframe!CISFBand::_DefWindowProc+0x75
    ieframe!CNotifySubclassWndProc::s_SubclassWndProc+0xb4
    comctl32!CallNextSubclassProc+0x3d
    comctl32!MasterSubclassProc+0x54
    user32!InternalCallWinProc+0x23
    user32!UserCallWinProcCheckWow+0x14b
    user32!DispatchClientMessage+0xda
    user32!__fnDWORD+0x24
    ntdll!KiUserCallbackDispatcher+0x2e
    user32!NtUserDispatchMessage+0xc
    user32!DispatchMessageWorker+0x38c
    user32!DispatchMessageW+0xf
    ieframe!CTabWindow::_TabWindowThreadProc+0x280
    kernel32!BaseThreadInitThunk+0xe
    ntdll!__RtlUserThreadStart+0x23
    ntdll!_RtlUserThreadStart+0x1b
    

    (Remember, you can get symbols for operating system binaries.)

    General debugging tip: If you see a really huge stack, that's a good sign that something interesting is going on. Boring stacks tend to be small.

    Furthermore, frames near the bottom of the stack tend to describe what the purpose of the thread is, whereas frames near the top of the stack tend to describe what the thread is actually doing right now. (Exercise: Why?)

    In this case, we see a stack that was probably created to manage a tab window (CTab­Window::_Tab­Window­Thread­Proc) and it's currently stuck in an I/O operation. You can then look at the file name to see what file is stuck.

    0:001> du 04cd6aac
    04cd6aac "\\server\share\abcdefg\Favorites\Mail.url"
    

    It looks like this user stored their Favorites on a network share that is not responding.

    The customer liaison replied,

    Thanks a lot for this information. Can you help me understand how do we tell that the dump indicates this file I/O is causing IE to hang? Having this information would help me better explain this to the customer.

    I wasn't sure how to respond to this. If you see a function with the words File and one of Open, Read, or Write in its name, there's a good chance that it opens, reads, or writes a file. You probably want to look to see what file is being opened, read from, or written to, because that may give a clue why the I/O operation is stuck.

    It turns out that this customer redirected the user's Favorites to a network location. The Internet Explorer folks tell me that this is not an explicitly supported scenario in the sense that they did not do any tuning to make this scenario work well, and frequent hangs are consequently not unexpected. If you redirect the Favorites to a network location, then you get what you get. And if that server frequently becomes unavailable, then what you get often sucks.

  • 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.

Page 2 of 427 (4,262 items) 12345»