• The Old New Thing

    How do I suppress the default animation that occurs when I hide or show a window?

    • 18 Comments

    A customer wanted to know how they can disable the default fade-in/fade-out animation that occurs when a window is hidden or shown. "I don't want to use WS_EX_TOOL­WINDOW because that causes my window to disappear from the taskbar. I tried Dwm­Enable­Composition but that affects the entire desktop and is too jarring. We want to suppress the effect because our program replaces one window with another, and we want the operation to be invisible to the user."

    Whoa, heading straight for Dwm­Enable­Composition? That's using a global solution to a local problem.

    To disable the animations on a specific window, use something like this:

    HRESULT DisableDwmAnimations(HWND hwnd)
    {
        BOOL fDisable = TRUE;
        return DwmSetWindowAttribute(hwnd,
                    DWMWA_TRANSITIONS_FORCEDISABLED,
                    &fDisable,
                    sizeof(fDisable));
    }
    

    Re-enabling the animations is left as an exercise for the reader.

  • The Old New Thing

    If a process crashes while holding a mutex, why is its ownership magically transferred to another process?

    • 29 Comments

    A customer was observing strange mutex ownership behavior. They had two processes that used a mutex to coordinate access to some shared resource. When the first process crashed while owning the mutex, they found that the second process somehow magically gained ownership of that mutex. Specifically, when the first process crashed, the second process could take the mutex, but when it released the mutex, the mutex was still not released. They discovered that in order to release the mutex, the second process had to call Release­Mutex twice. It's as if the claim on the mutex from the crashed process was secretly transferred to the second process.

    My psychic powers told me that that's not what was happening. I guessed that their code went something like this:

    // code in italics is wrong
    bool TryToTakeTheMutex()
    {
     return WaitForSingleObject(TheMutex, TimeOut) == WAIT_OBJECT_0;
    }
    

    The code failed to understand the consequences of WAIT_ABANDONED.

    In the case where the mutex was held by the first process when it crashed, the second process will attempt to claim the mutex, and it will succeed, and the return code from Wait­For­Single­Object will be WAIT_ABANDONED. Their code treated that value as a failure code rather than a modified success code.

    The second program therefore claimed the mutex without realizing it. That is what led the customer to believe that ownership was being magically transferred to the second program. It wasn't magic. The second program misinterpreted the return code.

    The second program saw that Try­To­Take­The­Mutex "failed", and it went off and did something else for a while. Then the next time it called Try­To­Take­The­Mutex, the function succeeded: It was a successful recursive acquisition, but the program thought it was the initial acquisition.

    The customer didn't reply back, so we never found out whether that was the actual problem, but I suspect it was.

  • The Old New Thing

    Answers to exercises

    • 0 Comments

    Exercise: Explain why we used 0x7FFF to represent infinite height.

    Answer: Commenter "Reiko" got this right. 0x7FFF is the maximum integer coordinate supported by Windows 95, 98 and Me.

    Exercise: Explain the line rcWindow.bottom += rcTemp.top.

    Answer: The more precise way of writing the line would have been

        rcWindow.bottom += (rcTemp.top - rcWindow.top) - (0 - rcWindow.top);
    
    The first term is the amount of non-client space consumed at the top of the window. The second term is the amount of non-client space consumed at the top of the window, taking wrapping into account. The difference, therefore is the amount by which AdjustWindowRectEx needs to be adjusted. But the two instances of rcWindow.top cancel out, leaving just rcTemp.top.
  • The Old New Thing

    "Super" watch, episode 2

    • 5 Comments

    Not just "super exciting" but "super-super-exciting". (But at least he's not super super super excited.) I don't consider this super encouraging.

    Episode 1.

  • The Old New Thing

    Rob Cockerham investigates those companies that pay cash for gold

    • 9 Comments

    Rob Cockerham seems to have a lot of spare time, which is great for the rest of us, because he investigates all those things we simply don't have the time for, and then posts the results on his Web site ("The sixth-best website in the world").

    Today's highlight is a pair of investigations he performed some time ago which seem to show two sides of one industry.

    That Web site is a sinkhole of time-wastage. If you're not careful, you'll find yourself clicking around from story to story, like the How much is inside? adventures, in which he investigates things like how many threads per inch are there in 360-thread count pillowcases? Or his gallery of costumes (for Hallowe'en or other events), including my favorite: Paparazzi.

  • The Old New Thing

    Restoring symbols to a stack trace originally generated without symbols

    • 10 Comments

    Has this ever happened to you?

    litware!Ordinal3+0x6042
    litware!DllInstall+0x4c90
    litware!DllInstall+0x4b9e
    contoso!DllGetClassObject+0x93c3
    contoso!DllGetClassObject+0x97a9
    contoso!DllGetClassObject+0x967c
    contoso!DllGetClassObject+0x94d7
    contoso!DllGetClassObject+0x25ce
    contoso!DllGetClassObject+0x2f7b
    contoso!DllGetClassObject+0xad55
    contoso!DllGetClassObject+0xaec7
    contoso!DllGetClassObject+0xadf7
    contoso!DllGetClassObject+0x3c00
    contoso!DllGetClassObject+0x3b2a
    contoso!DllGetClassObject+0x462b
    USER32!UserCallWinProcCheckWow+0x13a
    USER32!DispatchMessageWorker+0x1a7
    contoso!DllCanUnloadNow+0x19b6
    contoso!DllGetClassObject+0xeaf2
    contoso+0x1d6c
    litware!LitImportReportProfile+0x11c4
    litware!LitImportReportProfile+0x1897
    litware!LitImportReportProfile+0x1a3b
    KERNEL32!BaseThreadInitThunk+0x18
    ntdll!RtlUserThreadStart+0x1d
    

    Ugh. A stack trace taken without working symbols. (There's no way that Dll­Get­Class­Object is a deeply recursive 60KB function. Just by casual inspection, you know that the symbols are wrong.)

    To see how to fix this, you just have to understand what the debugger does when it has no symbols to work from: It uses the symbols from the exported function table. For every address it wants to resolve, it looks for the nearest exported function whose address is less than or equal to the target value.

    For example, suppose CONTOSO.DLL has the following exported symbols:

    Symbol Offset
    Dll­Get­Class­Object 0x5132
    Dll­Can­Unload­Now 0xFB0B

    Look at it this way: The debugger is given the following information about your module: (Diagram not to scale.)

     
      Dll­Get­Class­Object Dll­Can­Unload­Now

    It needs to assign a function to every byte in the module. In the absence of any better information, it does it like this:

    ??? Dll­Get­Class­Object Dll­Can­Unload­Now

    In words, it assumes that every function begins at the location specified by the export table, and it ends one byte before the start of the next function. The debugger is trying to make the best of a bad situation.

    Suppose your DLL was loaded at 0x10000000, and the debugger needs to generate a symbolic name for the address 0x1000E4F5.

    First, it converts the address into a relative virtual address by subtracting the DLL base address, leaving 0xE4F5.

    Next, it looks to see what function "contains" that address. From the algorithm described above, the debugger concludes that the address 0xE4F5 is "part of" the Dll­Get­Class­Object function, which began at begins at 0x5132. The offset into the function is therefore 0xE4F5 - 0x5132 = 0x93C3, and it is reported in the debugger as contoso!Dll­Get­Class­Object+0x93c3.

    Repeat this exercise for each address that the debugger needs to resolve, and you get the stack trace above.

    Fine, now that you know how the bad symbols were generated, how do you fix it?

    You fix it by undoing what the debugger did, and then redoing it with better symbols.

    You need to find the better symbols. This is not too difficult if you still have a matching binary and symbol file, because you can just load up the binary into the debugger in the style of a dump file. Like Doron, you can then let the debugger do the hard work.

    C:> ntsd -z contoso.dll
    
    ModLoad: 10000000 10030000   contoso.dll
    

    Now you just ask the debugger, "Could you disassemble this function for me?" You give it the broken symbol+offset above. The debugger looks up the symbol, applies the offset, and then looks up the correct symbol when disassembling.

    0:000> u contoso!DllGetClassObject+0x93c3
    contoso!CReportViewer::ActivateReport+0xe9:
    10000e4f5 eb05            jmp     contoso!CReportViewer::ActivateReport+0xf0
    

    Repeat for each broken symbol in the stack trace, and you have yourself a repaired stack trace.

    litware!Ordinal3+0x6042 ← oops
    litware!CViewFrame::SetInitialKeyboardFocus+0x58
    litware!CViewFrame::ActivateViewInFrame+0xf2
    contoso!CReportViewer::ActivateReport+0xe9
    contoso!CReportViewer::LoadReport+0x12c
    contoso!CReportViewer::OnConnectionCreated+0x13f
    contoso!CViewer::OnConnectionEvent+0x7f
    contoso!CConnectionManager::OnConnectionCreated+0x85
    contoso!CReportFactory::BeginCreateConnection+0x87
    contoso!CReportViewer::CreateConnectionForReport+0x20d
    contoso!CViewer::CreateNewConnection+0x87
    contoso!CReportViewer::CreateNewReport+0x213
    contoso!CViewer::OnChangeView+0xec
    contoso!CReportViewer::WndProc+0x9a7
    contoso!CView::s_WndProc+0xf1
    USER32!UserCallWinProcCheckWow+0x13a
    USER32!DispatchMessageWorker+0x1a7
    contoso!CViewer::MessageLoop+0x24e
    contoso!CViewReportTask::RunViewer+0x12
    contoso+0x1d6c ← oops
    litware!CThreadTask::Run+0x40
    litware!CThread::ThreadProc+0xe5
    litware!CThread::s_ThreadProc+0x42
    KERNEL32!BaseThreadInitThunk+0x18
    ntdll!RtlUserThreadStart+0x1d
    

    Oops, our trick doesn't work for that first entry in the stack trace, the one with Ordinal3. What's up with that? There is no function called Ordinal3!

    If your module exports functions by ordinal without a name, then the debugger doesn't know what name to print for the function (since the name was stripped from the module), so it just prints the ordinal number. You will have to go back to your DLL's DEF file to convert the ordinal back to a function name. Or you can dump the exports from the DLL to see what functions match up with what ordinals. (Of course, for that trick to work, you need to have a matching PDB file in the symbol search path.)

    In our example, suppose litware.dll ordinal 3 corresponds to the function Lit­Debug­Report­Profile. We would then ask the debugger

    0:001> u litware!LitDebugReportProfile+0x6042
    litware!CViewFrame::FindInitialFocusControl+0x66:
    1000084f5 33db            xor     ebx,ebx
    

    Okay, that takes care of our first oops. What about the second one?

    In the second case, the address the debugger was asked to generate a symbol for came before the first symbol in the module. In our diagram above, it was in the area marked with question marks. The debugger has absolutely nothing to work with, so it just disassembles as relative to the start of the module.

    To resolve this symbol, you take the offset and add it to the base of the module as it was loaded into the debugger, which was reported in the ModLoad output:

    ModLoad: 10000000 10030000   contoso.dll
    

    If that output scrolled off the screen, you can ask the debugger to show it again with the help of the lmm command.

    0:001>lmm contoso*
    start    end        module name
    10000000 10030000   contoso    (export symbols)       contoso.dll
    

    Once you have the base address, you add the offset back and ask the debugger what's there:

    0:001> u 0x10000000+0x1d6c
    contoso!CViewReportTask::Run+0x102:
    100001d6c 50              push    eax
    

    Okay, now that we patched up all our oopses, we have the full stack trace with symbols:

    litware!CViewFrame::FindInitialFocusControl+0x66
    litware!CViewFrame::SetInitialKeyboardFocus+0x58
    litware!CViewFrame::ActivateViewInFrame+0xf2
    contoso!CReportViewer::ActivateReport+0xe9
    contoso!CReportViewer::LoadReport+0x12c
    contoso!CReportViewer::OnConnectionCreated+0x13f
    contoso!CViewer::OnConnectionEvent+0x7f
    contoso!CConnectionManager::OnConnectionCreated+0x85
    contoso!CReportFactory::BeginCreateConnection+0x87
    contoso!CReportViewer::CreateConnectionForReport+0x20d
    contoso!CViewer::CreateNewConnection+0x87
    contoso!CReportViewer::CreateNewReport+0x213
    contoso!CViewer::OnChangeView+0xec
    contoso!CReportViewer::WndProc+0x9a7
    contoso!CView::s_WndProc+0xf1
    USER32!UserCallWinProcCheckWow+0x13a
    USER32!DispatchMessageWorker+0x1a7
    contoso!CViewer::MessageLoop+0x24e
    contoso!CViewReportTask::RunViewer+0x12
    contoso!CViewReportTask::Run+0x102
    litware!CThreadTask::Run+0x40
    litware!CThread::ThreadProc+0xe5
    litware!CThread::s_ThreadProc+0x42
    KERNEL32!BaseThreadInitThunk+0x18
    ntdll!RtlUserThreadStart+0x1d
    

    Now the fun actually starts: Figuring out why there was a break in CView­Frame::Find­Initial­Focus­Control. Happy debugging!

    Bonus tip: By default, ntsd does not include line numbers when resolving symbols. Type .lines to toggle line number support.

  • The Old New Thing

    I totally presented to an executive the wrong way

    • 10 Comments

    Some time ago, Gray Knowlton wrote an article on how to present to an executive.

    As you might have guessed, I've done it completely the wrong way.

    Many years ago, I was part of a group presenting to a senior-level executive. I was the one who wrote the document establishing the background for the topic and laying out the various options with their pros and cons. I wasn't the one doing the actual presenting, but I was asked to attend anyway, just in case the senior executive had a question that the presenters couldn't answer.

    For the duration of the meeting, I sat in the back and knitted.

    As it turns out, I wasn't needed. But at least I got some knitting done.

    (I was commended for the quality of the document I had written, so don't think I was just blowing off the issue entirely.)

  • The Old New Thing

    What does INIT_ONCE_CTX_RESERVED_BITS mean?

    • 11 Comments

    Windows Vista adds the One-Time Initialization family of functions which address a common coding pattern: I want a specific chunk of code to run exactly once, even in the face of multiple calls from different threads. There are many implementations of this pattern, such as the infamous double-checked lock. The double-checked lock is very easy to get wrong, due to memory ordering and race conditions, so the kernel folks decided to write it for you.

    The straightforward way of using a one-time-initialization object is to have it protect the initialization of some other object. For example, you might have it protect a static object:

    INIT_ONCE GizmoInitOnce = INIT_ONCE_STATIC_INIT;
    Gizmo ProtectedGizmo;
    
    BOOL CALLBACK InitGizmoOnce(
        PINIT_ONCE InitOnce,
        PVOID Parameter,
        PVOID *Context)
    {
        Gizmo *pGizmo = reinterpret_cast<Gizmo*>(Parameter);
        pGizmo->Initialize();
        return TRUE;
    }
    
    SomeFunction(...)
    {
        // Initialize ProtectedGizmo if not already initialized
        InitOnceExecuteOnce(&GizmoInitOnce,
                            InitGizmoOnce,
                            &ProtectedGizmo,
                            NULL);
    
        // At this point, ProtectedGizmo has been initialized
        ProtectedGizmo.Something();
        ...
    }
    

    Or you might have it protect a dynamic object:

    class Widget
    {
        Widget()
        {
            InitOnceInitialize(&m_InitOnce);
        }
    
        void Initialize();
    
        ...
    
        static BOOL CALLBACK InitWidgetOnce(
            PINIT_ONCE InitOnce,
            PVOID Parameter,
            PVOID *Context)
        {
            Widget *pWidget = reinterpret_cast<Widget*>(Parameter);
            pWidget->Initialize();
            return TRUE;
        }
    
        SomeMethod(...)
        {
            // Initialize ourselves if not already initialized
            InitOnceExecuteOnce(&InitWidgetOnce,
                                this,
                                NULL);
    
            // At this point, we have been initialized
            ... some other stuff ...
        }
    }
    

    But it so happens that you can also have the INIT_ONCE object protect itself.

    You see, once the INIT_ONCE object has entered the "initialization complete" state, the one-time initialization code only needs a few bits of state. The other bits are unused, so the kernel folks figured, "Well, since we're not using them, maybe the application wants to use them."

    That's where INIT_ONCE_CTX_RESERVED_BITS comes in. The INIT_ONCE_CTX_RESERVED_BITS value is the number of bits that the one-time initialization code uses after initialization is complete; the other bits are free for you to use yourself. The value of INIT_ONCE_CTX_RESERVED_BITS is 2, which means that you can store any value that's a multiple of 4. If it's a pointer, then the pointer must be DWORD-aligned or better. This requirement is usually easy to meet because heap-allocated objects satisfy it, and the pointer you want to store is usually a pointer to a heap-allocated object. As noted some time ago, kernel object handles are also multiples of four, so those can also be safely stored inside the INIT_ONCE object. (On the other hand, USER and GDI handles are not guaranteed to be multiples of four, so you cannot use this trick to store those types of handles.)

    Here's an example. First, the code which uses the traditional method of having the INIT_ONCE structure protect another variable:

    // using the static object pattern for simplicity
    
    INIT_ONCE PathInitOnce = INIT_ONCE_STATIC_INIT;
    LPWSTR PathToDatabase = NULL;
    
    BOOL CALLBACK InitPathOnce(
        PINIT_ONCE InitOnce,
        PVOID Parameter,
        PVOID *Context)
    {
        LPWSTR Path = (LPWSTR)LocalAlloc(LMEM_FIXED, ...);
        if (Path == NULL) return FALSE;
        ... get the path in Path...
        PathToDatabase = Path;
        return TRUE;
    }
    
    SomeFunction(...)
    {
        // Get the database path (initializing if necessary)
        if (!InitOnceExecuteOnce(&PathInitOnce,
                                 InitPathOnce,
                                 NULL,
                                 NULL)) {
            return FALSE; // couldn't get the path for some reason
        }
    
        // The "PathToDatabase" variable now contains the path
        // computed by InitPathOnce.
    
        OtherFunction(PathToDatabase);
        ...
    }
    

    Since the object being protected is pointer-sized and satisfies the necessary alignment constraints, we can merge it into the INIT_ONCE structure.

    INIT_ONCE PathInitOnce = INIT_ONCE_STATIC_INIT;
    
    BOOL CALLBACK InitPathOnce(
        PINIT_ONCE InitOnce,
        PVOID Parameter,
        PVOID *Context)
    {
        LPWSTR Path = (LPWSTR)LocalAlloc(LMEM_FIXED, ...);
        if (Path == NULL) return FALSE;
        ... get the path in Path...
        *Context = Path;
        return TRUE;
    }
    
    SomeFunction(...)
    {
        LPWSTR PathToDatabase;
        // Get the database path (initializing if necessary)
        if (!InitOnceExecuteOnce(&PathInitOnce,
                                 InitPathOnce,
                                 NULL,
                                 &PathToDatabase)) {
            return FALSE; // couldn't get the path for some reason
        }
    
        // The "PathToDatabase" variable now contains the path
        // computed by InitPathOnce.
    
        OtherFunction(PathToDatabase);
        ...
    }
    

    This may seem like a bunch of extra work to save four bytes (or eight bytes on 64-bit Windows), but if you use the asynchronous initialization model, then you have no choice but to use context-based initialization, as we learned when we tried to write our own lock-free one-time initialization code.

  • The Old New Thing

    There's only so much you can do to stop running code from simulating UI actions

    • 33 Comments

    Commenter KiwiBlue asks whether Captcha-style tests were considered to prevent unsigned drivers from programmatically clicking the 'Install anyway' button.

    I'm sure somebody considered it, but Captcha has its own problems.

    "Type the (distorted) letters below"-type Captcha cannot be used by people with visual impairments, people who are dyslexic, or people who simply are not familiar with the Latin alphabet. (Believe it or not, the vast majority of people on the planet have a native language which does not use the Latin alphabet.) Using an audio captcha runs into the problem of different accents, letters whose readings vary (zee/zed anyone?), and computers without a sound card (like most servers).

    And yes, there are other types of Captchas (dog/cat, for example), but the strongest argument against Captcha is probably that it's just adding more locks to the front door while leaving the service entrance wide open. Once you make it computationally infeasible to programmatically solve the Captcha, unscrupulous driver vendors would simply inject a DLL into the "Install this unsigned driver?" process and patch the call to Did­User­Answer­Captcha­Correctly so it always returns TRUE.

    Or even easier, just programmatically set the Driver Signing Options to Install the software anyway.

    If somebody is running code with administrative privileges, then they already own your machine. Any roadblocks you put up they can find a way to drive over. The goal is not so much putting up stronger and stronger roadblocks (because eventually people will simply drive around them) but rather making it clear to the developer that what they're doing is driving around a roadblock.

  • The Old New Thing

    See you in Building 109, Conference Room A

    • 7 Comments

    We saw some time ago that if somebody invites you to a meeting in Building 7, they are inviting you off campus to take a break from work.

    If somebody invites you to a meeting in Building 109, Conference Room A, they are inviting you to join them at the Azteca Mexican restaurant next door.

    Update: One of the members of the "Building 109 Conference Room A" mailing list informed me that Building 109 Conference Room A is specifically the bar at the Azteca restaurant.

    Update 2: Building 109 Conference Room A has its own mailing list!

Page 375 of 451 (4,502 items) «373374375376377»