October, 2008

  • The Old New Thing

    Disable your wireless network card to speed up VPN'ing

    • 8 Comments

    As a follow-up to my tip on speeding up connecting via RAS and a SmartCard, I've been told that another trick you can do is to disable your wireless networking card before initiating the VPN connection. Wireless networking cards are a huge attack surface, and the VPN software spends a lot of time trying to secure it.

    I don't have a wireless networking card on the machine I use at home to connect to the work network, so I haven't tried it, but who knows, maybe it'll work for you.

  • The Old New Thing

    Why does Task Manager let me kill critical system processes?

    • 30 Comments

    Because you told it to.

    If you run Task Manager, highlight a critical system process like Winlogon, click End Task, and confirm, then gosh darn it, you just killed Winlogon, and the system will reboot. (Assuming, of course, that you have sufficient privileges to terminate Winlogon in the first place.)

    Task Manager in earlier versions of Windows would try to stop you from killing these critical system processes, but its algorithm for deciding which processes were critical wasn't very smart, and if you were sufficiently devious, you could fake it out and make your program seemingly unkillable.¹

    To avoid being faked out, Task Manager simply stopped trying. Because if you don't do anything, then you can't do it wrong.

    Footnotes

    ¹Of course, it was no such thing. You could still kill the program; you just had to use a program other than Task Manager to do it. (For example, you might try taskkill.)

  • The Old New Thing

    Why does killing Winlogon take down the entire system?

    • 29 Comments

    Commenter Demeli asks, "Why does Winlogon take down the entire system when you attach a debugger to it? (drwtsn32 -p <pid of Winlogon>)"

    This question already has a mistaken in it. Running drwtsn32 on a process isn't attaching a debugger to it. Attaching a debugger would be something like ntsd -p <pid of Winlogon>, and this does work, assuming you have the necessary privileges, of course. (Indeed, this is how the Windows team debugs problems with Winlogon.) In other words, the literal answer to the question is "No, Winlogon does not take down the entire system when you attach a debugger to it."

    What drwtsn32 does is take a crash dump of the process and then kills the target process. And it is killing Winlogon that crashes the system.

    Winlogon is what is known as a "critical system process", the death of which forces a system restart. And you can probably guess why the system considers Winlogon critical to its functioning. For example, Winlogon is responsible for handling the secure attention sequence, also known as Ctrl+Alt+Del. If Winlogon were to die, then the secure attention sequence would stop working. That's kind of bad.

  • The Old New Thing

    How do I suppress the CapsLock warning on password edit controls?

    • 25 Comments

    One of the features added to version 6 of the shell common controls is a warning balloon that appears if CapsLock is on in a password control. Let's demonstrate. Take the scratch program, add a manifest that requests version 6 of the common controls (perhaps by using a Visual C++ extension), and add the following:

    BOOL
    OnCreate(HWND hwnd, LPCREATESTRUCT lpcs)
    {
        g_hwndChild = CreateWindow(TEXT("edit"), NULL,
                ES_PASSWORD | WS_CHILD | WS_VISIBLE, 0, 0,
                0, 0, hwnd, NULL, g_hinst, 0);
        if (!g_hwndChild) return FALSE;
    
        return TRUE;
    }
    

    Run this program and hit the CapsLock key. The warning balloon should appear. (If it doesn't, then your manifest is probably not working.)

    Suppose you want to suppress this warning balloon. Why? I don't know. Maybe you want to confuse your user. Maybe you think it looks ugly. Whatever the reason, you can suppress the balloon by subclassing the edit control and swallowing the EM_SHOWBALLOONTIP message.

    WNDPROC g_wpEdit;
    
    LRESULT CALLBACK NoBalloonWndProc(HWND hwnd, UINT uMsg,
                                      WPARAM wParam, LPARAM lParam)
    {
      switch (uMsg) {
      case EM_SHOWBALLOONTIP: return FALSE;
      }
      return CallWindowProc(g_wpEdit, hwnd, uMsg, wParam, lParam);
    }
    
    BOOL
    OnCreate(HWND hwnd, LPCREATESTRUCT lpcs)
    {
        g_hwndChild = CreateWindow(TEXT("edit"), NULL,
                ES_PASSWORD | WS_CHILD | WS_VISIBLE, 0, 0,
                0, 0, hwnd, NULL, g_hinst, 0);
        if (!g_hwndChild) return FALSE;
    
        g_wpEdit = SubclassWindow(g_hwndChild, NoBalloonWndProc);
    
        return TRUE;
    }
    

    When you run this modified program, you'll see that the balloon tip no longer appears because the subclass procedure intercepts all the balloon tips before the default edit control window procedure can see them.

    [Raymond is currently away; this message was pre-recorded.]

  • The Old New Thing

    How can I increase the number of files I can open at a time?

    • 33 Comments

    People who ask this question invariably under-specify the question. They just say, "How can I increase the number of files I can open at a time?" without saying how they're opening them. From the operating system's point of view, the number of files you can open at a time is limited only by available resources. Call CreateFile until you drop. (This remark applies to local files. When you talk over the network, things get weirder.)

    The fact that these people are asking the question, however, indicates that they're not using CreateFile to open the files. They're using some other intermediate layer, and it's that layer that is imposing some sort of limit. You'll have to investigate that layer to see what you can do about raising the limit.

    [Raymond is currently away; this message was pre-recorded.]

  • The Old New Thing

    Why does the Disk Management snap-in report my volume as Healthy when the drive is dying?

    • 41 Comments

    Windows Vista displays a big scary dialog when the hard drive's on-board circuitry reports that the hardware is starting to fail. Yet if you go to the Disk Management snap-in, it reports that the drive is Healthy. What's up with that?

    The Disk Management snap-in is interested in the logical structure of the drive. Is the partition table consistent? Is there enough information in the volume to allow the operating system to mount it? It doesn't know about the drive's physical condition. In other words, "As far as the Disk Management snap-in is concerned, the drive is healthy."

    Similarly, your car's on-board GPS may tell you that you are on track for a 6pm arrival at your destination, unaware that you have an oil leak that is going to force you to the side of the road sooner or later. All the GPS cares about is that the car is travelling along the correct road.

    [Raymond is currently away; this message was pre-recorded.]

  • The Old New Thing

    Microspeak: Teaming

    • 12 Comments

    At training sessions, you don't participate in team-building exercises. No, that's old-fashioned terminology, the sort of thing those old stodgy Web 1.0 dinosaurs would say. The new word is teaming.

    Note: This Microspeak entry was submitted by a colleague from the UK, so it may be peculiar to the UK dialect of Microspeak.

    Pre-emptive clever comment: Verbing weirds language.

    [Raymond is currently away; this message was pre-recorded.]

  • The Old New Thing

    Eventually, nothing is special any more

    • 25 Comments

    Commenter ulric suggested that two functions for obtaining the "current" window should exist, one for normal everyday use and one for "special use" when you want to interact with windows outside your process.

    I'd be more at ease however if the default behaviour of the API was to return HWND for the current process only, and the apps that really need HWND from other potentially other processes would have to be forced to use another API that is specifically just for that.

    This is an excellent example of suggesting something that Windows already does. The special function has become so non-special, you don't even realize any more that it's special.

    Originally, in 16-bit Windows, the function for getting the "current" window was GetActiveWindow. This obtained the active window across the entire system. One of the major changes in Win32 is the asynchronous input model, wherein windows from different input queues receive separate input. That way, one program that has stopped responding to input doesn't clog up input for other unrelated windows. Win32 changed the meaning of GetActiveWindow to mean the active window from the current input queue.

    In 16-bit Windows, there was only one input queue, the global one. In 32-bit Windows, each thread (or group of input-attached threads) gets its own input queue.

    As a result of this finer granularity, when a program was ported from 16-bit Windows to 32-bit Windows, it didn't "see" windows from other programs when it called functions like GetFocus or GetActiveWindow. As every Win32 programmer should know, these states are local to your input queue.

    Okay, let's look at what we've got now. GetFocus and GetActiveWindow give you the status of your input queue. In other words, in a single-threaded program (which, if you're coming from 16-bit Windows, is the only type of program there is), calling GetActiveWindow gives you the active window from your program. It doesn't return the active window from another program.¹ Things are exactly as ulric suggested!

    Now let's look at the second half of the suggestion. If a program really needs to get a window from potentially other processes, it would have to use some other function that is specifically just for that. And indeed, that's why the GetForegroundWindow function was added. The GetForegroundWindow function is the special function specifically designed for obtaining windows from other processes.

    Therefore, we did exactly what ulric recommended, and it still turned into a mess. Why?

    Because once you create something special, it doesn't remain special for long.

    It may take a while, but eventually people find that the regular function "doesn't work" (for various definitions of "work"), and they ask around for help. "When I call GetActiveWindow, I'm not getting the global active window; I'm just getting the local one. How do I get the global one?" Actually, they probably don't even formulate the question that clearly. It's probably more like "I want to get the active window, but GetActiveWindow doesn't work."

    And then somebody responds with "Yeah, GetActiveWindow doesn't work. I've found that GetForegroundWindow works a lot better."

    The response is then "Wow, that works great! Thanks!"

    Eventually, the word on the street is "GetActiveWindow doesn't work. Use GetForegroundWindow instead." Soon, people are using it for everything, waxing their car, calming a colicky baby, or improving their sexual attractiveness.

    What used to be a function to be used "only in those rare occasions when you really need it" has become "the go-to function that gets the job done."

    In fact, the unfashionableness of the active window has reached the point that people have given up on calling it the active window at all! Instead, they call it the foreground window from the current process. It's like calling a land line a "wired cell phone".

    Requiring a new flag to get the special behavior doesn't change things at all. It's the same story, just with different names for the characters. "GetFocalWindow² doesn't work unless you pass the GFW_CROSSPROCESS flag." Soon, everybody will be passing the GFW_CROSSPROCESS not because they understand what it does but just because "That's what I was told to do" and "It doesn't work if I don't pass it."

    Footnotes

    ¹Assuming you haven't run around attaching your thread to some other program's input queue. This is a pretty safe assumption since the AttachThreadInput function didn't exist in 16-bit Windows either.

    ²GetFocalWindow is an imaginary function created for the purpose of the example.

    [Raymond is currently away; this message was pre-recorded.]

  • The Old New Thing

    Stories of crossing into Canada: The wedding

    • 19 Comments

    When I cross the border into Canada, there's almost always a story. Rarely is there an uneventful crossing.

    In 2007, I attended a wedding in Vancouver, BC, and here's how the conversation went at the border crossing into Canada:

    Me: Good morning. (As I hand over passports and green cards for everybody in the car.)

    Border guard: Hello. What is the purpose of your visit?

    Me: A wedding.

    Border guard: How long will you be in Canada? (Looks over the documents and compares the faces against the people in the car.)

    Me: Just one day.

    Border guard: Bringing any gifts?

    I didn't bring any gifts (in the traditional Western sense), but maybe the other guests did. I look to the passenger sitting next to me.

    Passenger: No.

    Border guard: No gifts?

    Passenger: Just hong bao. Red envelopes with money.

    The border guard is by now completely confused and gives us a look like, "Didn't your mother teach you anything? You're showing up at a wedding empty-handed? Well, it's too late now. I'm certainly not going to try to teach you proper manners. You're on your own."

    Border guard: (Hands us our papers and waves us through.) All right.

    Vancouver has a large Chinese community, the largest in all of Canada. About ten percent of the B.C. population is ethnic Chinese, and Mandarin and Cantonese are the mother tongues in 30 percent of Vancouver homes. This was a relative young person, so who knows, maybe the border guard was new on the job. But you'd think that even after just one summer working the Canadian border near Vancouver, the guard would have encountered at least a few red envelopes by now.

    Bonus chatter: One of my friends often visits her family in Canada for birthdays and other family events. When she does so, she buys the gift in Canada or has some other plan that avoids having to carry the gift across the border. The conversation at the border is similar to the one I described above, where the border guard asks if she is bringing any gifts, and she answers that she isn't. My friend figures that in a database somewhere in the Ministry of Public Safety, they have a record on her that simply reads, "Cheapskate."

    [Raymond is currently away; this message was pre-recorded.]

  • The Old New Thing

    Acquire and release sound like bass fishing terms, but they also apply to memory models

    • 12 Comments

    Many of the normal interlocked operations come with variants called InterlockedXxxAcquire and InterlockedXxxRelease. What do the terms Acquire and Release mean here?

    They have to do with the memory model and how aggressively the CPU can reorder operations around it.

    An operation with acquire semantics is one which does not permit subsequent memory operations to be advanced before it. Conversely, an operation with release semantics is one which does not permit preceding memory operations to be delayed past it. (This is pretty much the same thing that MSDN says on the subject of Acquire and Release Semantics.)

    Consider the following code fragment:

    int adjustment = CalculateAdjustment();
    while (InterlockedCompareExchangeAcquire(&lock, 1, 0) != 0)
      { /* spin lock */ }
    for (Node *node = ListHead; node; node = node->Next)
       node->value += adjustment;
    InterlockedExchangeRelease(&lock, 0);
    

    Applying Acquire semantics to the first operation operation ensures that the operations on the linked list are performed only after the lock variable has been updated. This is obviously desired here, since the purpose of the updating the lock variable is ensure that no other threads are updating the list while we're walking it. Only after we have successfully set the lock to 1 is it safe to read from ListHead. On the other hand, the Acquire operation imposes no constraints upon when the store to the adjustment variable can be completed to memory. (Of course, there may very well be other constraints on the adjustment variable, but the Acquire does not add any new constraints.)

    Conversely, Release semantics for an interlocked operation prevent pending memory operations from being delayed past the operation. In our example, this means that the stores to node->value must all complete before the interlocked variable's value changes back to zero. This is also desired, because the purpose of the lock is to control access to the linked list. If we had completed the stores after the lock was released, then somebody else could have snuck in, taken the lock, and, say, deleted an entry from the linked list. And then when our pending writes completed, they would end up writing to memory that has been freed. Oops.

    The easy way to remember the difference between Acquire and Release is that Acquire is typically used when you are acquiring a resource (in this case, taking a lock), whereas Release is typically used when you are releasing the resource.

    As the MSDN article on acquire and release semantics already notes, the plain versions of the interlocked functions impose both acquire and release semantics.

    Bonus reading: Kang Su discusses how VC2005 converts volatile memory accesses into acquires and releases.

    [Raymond is currently away; this message was pre-recorded.]

Page 3 of 4 (33 items) 1234