• The Old New Thing

    How come the technique for launching an unelevated process from an elevated process doesn't work?


    A customer was following the Execute in Explorer sample to launch an unelevated process from an elevated process. (A sample which I rehashed some time ago.) The customer reported that the resulting process was still elevated.

    Upon closer inspection, the customer had disabled User Account Control (UAC).

    If UAC is disabled, then the ability for an administrative user to launch an unelevated process no longer exists.

    Since people like tables, here are some tables.

    In the classical world without UAC, administrators are administrators, and standard users are standard users. In other words, processes run by administrators are always elevated, and processes run by standard users are always non-elevated.

    UAC disabled
    User type Process type
    Elevated Non-elevated

    UAC added a new option to the table: The administrator who voluntarily relinquishes administrative privilege and runs a process non-elevated.

    UAC enabled
    User type Process type
    Elevated Non-elevated

    In words: In the classic non-UAC world, an administrative user can run processes elevated, and a standard user can run processes un-elevated. If UAC is enabled, then a new combination becomes available: An administrative user can run a process non-elevated.

    If you disable UAC, then you are back in the classic world, where there is no such thing as an administrative user running a non-elevated process. It's therefore no surprise that when you try to run the process unelevated, it still runs elevated.

    You can look at this issue another way: If UAC is disabled, then Explorer runs elevated. And therefore, if you ask Explorer to run a process, that process runs elevated too.

    It turns out that the customer turned off UAC because they didn't want to see any UAC prompts; they wanted their program to elevate silently, yet launch child processes unelevated. From a security-theoretical point of view, this is not an interesting configuration: If you allow silent elevation, then those child processes can just silently elevate themselves, and your attempt to run them unelevated accomplished nothing.

    If you disable UAC, then the only way to get both elevated processes and unelevated processes is to run the elevated processes as one user (an administrator) and the unelevated processes as another user (a standard user).

  • The Old New Thing

    When you think you found a problem with a function, make sure you're actually calling the function


    On an internal mailing list, a tester asked if there were any known problems with the Find­First­File­Ex function preventing a directory from being deleted and recreated.

    Our code creates a test folder, then calls Find­First­File­Ex to look inside the test folder. When we're done, we call Find­Close, then delete the directory. When we try running the test twice, the second time fails to create the test folder; we get ERROR_ACCESS_DENIED. But if we switch to Find­First­File instead of Find­First­File­Ex, then everything works as expected.

    Here's our code, simplified.

    // Assume all functions succeed except where indicated.
    CreateDirectory(L"C:\\Test", NULL);
    // This version works:
    // WIN32_FIND_DATA data;
    // HANDLE hFindFile = FindFirstFile(L"C:\\Test\\*", &data);
    // This version doesn't:
    WIN32_FIND_DATA data;
    HANDLE hFindFile = FindFirstFileEx(L"C:\\Test\\*",
    // If we used FindFirstFile, then this CreateDirectory succeeds.
    // If we used FindFirstFileEx, then this CreateDirectory fails.
    CreateDirectory(L"C:\\Test", NULL);

    I suggested that they try running their test with anti-malware software disabled. Anti-malware software will frequently intrude on file operations, and it could be that the virus scanner is still checking the old C:\Test directory when you get around to creating the new one. Content indexers are another case where this can happen, but content indexers tend to wait until the machine is quiet rather than introducing on actions as they occur. (Now, well-written virus scanners and content indexers know to do things like abandon a file scan when a delete request is made, or use opportunistic locks to get out of the way when an application wants to do something with a file being scanned. But not all virus scanners and content indexers as as well-written as we might like.)

    We later heard back that they figured out the problem, and it wasn't because of a virus scanner or content indexing service.

    The problem was that their code was running inside a test harness, and that test harness had mocked the Find­First­File and Find­Close functions, but it did not mock the Find­First­File­Ex function. When the mock Find­Close function was given a handle created by the real Find­First­File­Ex function, it got confused and ended up leaking the directory handle. The Remove­Directory function succeeded, but the directory was not fully removed due to the outstanding handle, and the attempt to recreate the directory therefore failed.

    The tester also confirmed that the problem did not exist when they ran the code outside the test environment.

    When you think you found a problem with a function, make sure you're actually calling the function. In this case, the code was running under nonstandard conditions: The test harness had redirected a bunch of OS functions. As a result, when the code called Find­Close, it wasn't actually calling Find­Close but rather a mock function provided by the test harness.

    To be fair, the tester was new to the team and was likely not even aware that the test harness was mocking file I/O functions in the first place.

    If you are having trouble with a function, one thing to check is that you're actually calling the function.

  • The Old New Thing

    One way to make sure nobody reports problems with your Web site


    I had ordered a service online, and the Web site said, "Do not close this window until you are done, because once you close the window, you won't be able to come back."

    Okay, fine. I just need to make sure I get everything I need before I close the window.

    I click a link to download some of the information I had ordered, and I get the error message:

    We're having trouble processing your request.
    If this problem persists please let us know.
    Email us at null


  • The Old New Thing

    How can I reposition my window so it isn't covered by the touch keyboard?


    Last week, we saw how we could rearrange our window contents to avoid having the touch keyboard cover the edit control. But what if the touch keyboard covers the entire window? No amount of rearranging will help. We'll have to move our window.

    Let's make these changes to the Do­Layout function:

    DoLayout(HWND hwnd, int cx, int cy, bool isKeyboardShowing = false)
      if (g_hwndChild) {
          if (IntersectRect(&rc, &rcEdit, &rcKeyboardClient)) {
            if (rcKeyboardClient.top > 50) {
              cyEdit = min(rcKeyboardClient.top, cy);
            } else if (isKeyboardShowing) {
              // need to reposition the entire window, ugh.
              int dyAdjust = 50 - rcKeyboardClient.top;
              RECT rcWindow;
              GetWindowRect(hwnd, &rcWindow);
              SetWindowPos(hwnd, nullptr,
                rcWindow.left, rcWindow.top - dyAdjust, 0, 0,

    If there are at least 50 pixels of the edit control visible, then we consider that good enough. If not, and if we are responding to the keyboard showing, then we take matters into our own hands and move our window so that there are 50 pixels of the edit control visible. I didn't bother adding a check to make sure we never moved beyond the top of the work area; I'll leave that as an exercise for the reader, seeing as it's more typing that tends to distract from the point of the article.

  • The Old New Thing

    How can I force a CreateFile call to hang, in order to test something?


    A customer was doing some testing and wanted to know if there was a way to force a call to Create­File to hang, so that they can test their program's hang detection and recovery code.

    You can ceate these scenarios with careful use of opportunistic locks (also known as oplocks). The sample program I wrote some time ago can be used, for example, to cause a Create­File call requesting write access to hang until the oplock is released.

    To cause a Create­File call requesting read access to hang until the oplock is released, use OPLOCK_LEVEL_CACHE_WRITE; this means that the oplock owner caching writes, so nobody can read from the file until the cached writes are flushed out.

  • The Old New Thing

    Keep your eye on the code page: Is this string CP_ACP or UTF-8?


    A customer had a problem with strings and code pages.

    The customer has a password like "Müllwagen" for a particular user. Note the umlaut over the u. That character is encoded as the two bytes C3 BC according to UTF-8. When the customer passes this password to the Logon­User function in order to authenticate the user, the call fails, claiming that the password is invalid.

    If we encode the ü as the single byte FC, then the call to Logon­User succeeds.

    Therefore, if the string is in UTF-8 form, it needs to be converted, and to do this we use the Multi­Byte­To­Wide­Char function. Once converted, the logon is successful.

    The problem is that we are not sure if the password being given to the application will encode the ü as C3 BC or as FC. If it arrives as FC, and we try to convert it with the Multi­Byte­To­Wide­Char function, the ü is converted to U+FFFD.

    If I take the FC-encoded string and convert it with the Multi­Byte­To­Wide­Char function, passing CP_ACP as the first parameter, then it converts successfully (no U+FFFD), and the call to Logon­User is successful.

    For the application, the customer does not want to distinguish the two cases or implement any retry logic or anything like that. Can you help us understand the issue, what we are doing wrong, and how we can fix it?

    As the problem is stated, you are screwed.

    You have a bunch of bytes, and you don't know what encoding they are in. The byte sequence C3 BC might be a UTF-8 encoding of ü, or it could be a CP_ACP encoding of ý. You are stuck with guessing. But for something as important as passwords, you shouldn't guess. You need to know for sure, because an incorrect guess will generate audit entries, and may cause the user to become locked out of the account due to too many incorrect passwords.

    This means that you need to make sure that whoever is passing you the string also tells you what encoding it is using.

    The customer liaison replied,

    Thanks. I went back and talked to the customer, and it turns out that the password is always in UTF-8 form, so the problem is solved. We will always pass CP_UTF8 when converting the string.

  • The Old New Thing

    Taking ownership of a file doesn't give you access, yet


    A colleague of mine accidentally ran a command from an elevated command prompt rather than a normal unelevated command prompt. By default, files created from an elevated command prompt are owned by the Administrators group, on the theory that you are doing work in the elevated command prompt in your rôle as the system administrator, so the things you are doing are done on behalf of all the administrators of the system. (If you don't like this you can use the Default owner for objects created by members of the Administrators group policy to change the default.)

    My colleague attempted to repair the damage by taking ownership of all the files back: From the root of the directory tree of files that got created with the wrong owner, he ran takeown /f . /r to take them back. (You naturally have to do this from an elevated command prompt. Since you left off the /A flag, this assigns ownership to you personally, rather than to the administrators group.)

    "I can confirm that I am the owner by using the dir /q command, but I still don't have access. What gives?"

    Having ownership of a file does not automatically grant you full access. Users always have WRITE_DAC permission on objects they own, but that's all. If you want more, you need to leverage WRITE_DAC into full access.

    Fortunately, leveraging WRITE_DAC into full access is easy, because WRITE_DAC gives you permission to change permissions, so you can just change the permission to grant yourself full access:

    cacls /e /g domain\user:F
  • The Old New Thing

    Bitter or acerbic? or does it make a difference?


    One of my colleagues told me that my name came up in conversation, and somebody said that they thought I had a reputation for being bitter.

    My colleague defended me. "Nah, Raymond isn't bitter. He's, I dunno, acerbic."

    "Acerbic? What does that mean?"

    My colleague looked it up.

    "It means, um... bitter."

  • The Old New Thing

    How can I reposition my controls so they aren't covered by the touch keyboard?


    Last week, we saw how to tell the Windows 8 touch keyboard to appear automatically in a desktop program when focus enters an edit control. But we did nothing to prevent the touch keyboard from covering the edit control.

    To find out when the touch keyboard appears and disappears, you register with the framework input pane. The framework input pane tells you the current location of the keyboard and informs you when the keyboard state changes. (Note that it does not tell you about the keyboard when it is in floating mode, on the theory that when the user floats the keyboard, the user has taken responsibility for making sure it doesn't cover anything interesting.)

    Take our program from last week and make these changes:

    #include <strsafe.h>
    using namespace Microsoft::WRL;
    // Add immediately before DoLayout
    ComPtr<IFrameworkInputPane> g_frameworkInputPane;
    DWORD g_cookie;
    RECT g_rcKeyboard;

    In a real program, of course, we wouldn't use global variables, but this is a Little Program.

    void Relayout(HWND hwnd,
      bool isKeyboardShowing = false);
    class Handler : public RuntimeClass<
      Handler(HWND hwnd) : m_hwnd(hwnd) { }
      STDMETHODIMP Hiding(BOOL fEnsureFocusedElementInView) override
        return S_OK;
      STDMETHODIMP Showing(RECT *prcScreenLocation,
          BOOL fEnsureFocusedElementInView) override
        g_rcKeyboard = *prcScreenLocation;
        Relayout(m_hwnd, true);
        return S_OK;
      HWND m_hwnd;

    Our Handler class implements the IFramework­Input­Pane­Handler interface so it can be called when the input pane shows and hides. When this happens, we update the keyboard rectangle and ask our window to update its layout in response to the new information. We pass a special flag that indicates whether the call is in response to the keyboard showing, because we want to do extra work in that case.

    DoLayout(HWND hwnd, int cx, int cy, bool isKeyboardShowing = false)
      // Just for fun, put the keyboard position in the title bar.
      if (IsRectEmpty(&g_rcKeyboard)) {
        SetWindowText(hwnd, TEXT("Keyboard is not visible"));
      } else {
        TCHAR message[256];
        StringCchPrintf(message, ARRAYSIZE(message),
          TEXT("Keyboard is at (%d,%d)-(%d,%d)"),
          g_rcKeyboard.left, g_rcKeyboard.top,
          g_rcKeyboard.right, g_rcKeyboard.bottom);
        SetWindowText(hwnd, message);
      if (g_hwndChild) {
        int cyEdit = cy;
        if (!IsRectEmpty(&g_rcKeyboard)) {
          RECT rcEdit = { 0, 0, cx - 100, cy };
          RECT rcKeyboardClient = g_rcKeyboard;
          MapWindowRect(nullptr, hwnd, &rcKeyboardClient);
          RECT rc;
          if (IntersectRect(&rc, &rcEdit, &rcKeyboardClient)) {
            cyEdit = min(rcKeyboardClient.top, cy);
        MoveWindow(g_hwndChild, 0, 0, cx - 100, cyEdit, TRUE);
        if (isKeyboardShowing) {
          SendMessage(g_hwndChild, EM_SCROLLCARET, 0, 0);
      if (g_hwndButton) {
        MoveWindow(g_hwndButton, cx - 100, 0, 100, 50, TRUE);

    First, we update the title bar to show where we think the keyboard is, just so it's easier to follow what's happening. And then the actual action: If the keyboard is visible and it overlaps the edit control, then we resize the edit control to avoid it. And if the keyboard is showing, then we scroll the edit control so that the caret is visible. We don't want to force the caret visible in the general case, because that would cause the contents to scroll at unexpected times.

    OnMove(HWND hwnd, int x, int y)

    When the window moves, we want to perform relayout, because the window may have moved in such a way that the edit control is obscured by the keyboard.

    Relayout(HWND hwnd, bool isKeyboardShowing);
      RECT rc;
      GetClientRect(hwnd, &rc);
      DoLayout(hwnd, rc.right, rc.bottom, isKeyboardShowing);
    This function is kind of anticlimactic. To perform relayout, we get the client rectangle and ask DoLayout to lay out the contents inside that rectangle.

    OnCreate(HWND hwnd, LPCREATESTRUCT lpcs)
      CoCreateInstance(__uuidof(FrameworkInputPane), nullptr,
        CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&g_frameworkInputPane));
      return TRUE;

    Here is how the ball gets set into motion: When we create the window, we also register our handler with the framework input pane, so that we are called back when the keyboard moves.

    OnDestroy(HWND hwnd)
      if (g_cookie) {
      g_frameworkInputPane = nullptr;

    And some bookkeeping: When the window is destroyed, we unregister from the framework input pane. We also need to release the framework input pane before COM get uninitialized. (This wouldn't have been necessary if we had put the framework input pane in a member variable, since the member variable would be destructed at window destruction. But we were lazy and used a global variable, and now we pay the price.)

    If you take this program out for a ride, you'll see that it manages to resize the edit control so that it is not covered by the touch keyboard. But there's still a problem: What if the window is near the bottom of the screen, and the user calls up the touch keyboard? The entire edit control ends up obscured! No amount of resizing will fix this. We'll look at this problem next time.

  • The Old New Thing

    There is no /8TB flag on 64-bit Windows


    A customer reported that their 64-bit application was crashing on Windows 8.1. They traced the problem back to the fact that the user-mode address space for 64-bit applications on Windows 8.1 is 128TB, whereas it was only 8TB on earlier versions of Windows for x64. They wanted to know whether there was a compatibility mode that they could set for their application to say "Give me only 8TB please."

    No, there is no compatibility mode to shrink the user-mode address space down to 8TB.¹ You get it all, like it or not.

    Allowing 64-bit applications to opt out of the 128TB address space has implications for the rest of the system, such as reducing the strength of ASLR.

    As for how they ended up having a dependency on the address space being at most 8TB, they didn't say, but I have a guess: They are using the unused bits for tagging.

    If you are going to use tagged pointers, you need to put your tag bits in the least significant bits, since those are bits you control. For example, if you align all your objects on 16-byte boundaries, then you have four available bits for tagging. If you're going to use upper bits for tagging, at least verify that those upper bits are available.

    ¹ If anything, the user-mode address space will only grow over time. The original 8TB limit in earlier versions of Windows was due to the lack of a CMPXCHG16B instruction, but now that the instruction is available (and support for it deemed mandatory), the full 256TB address space is available to the operating system, and right now, it decides to split the address space evenly between user mode and kernel mode.

Page 7 of 458 (4,573 items) «56789»