• The Old New Thing

    A trick for finding the correct internal mailing list

    • 12 Comments

    Suppose you have a problem and you want to report it to an internal mailing list, but you don't know the correct mailing list to use. Here's a trick that apparently is not that well-known, though perhaps that's a reflection on people's lack of creativity than any inherent difficulty in execution.

    For example, suppose you have a problem with the file system. One thing you can try is to go to the company Address Book and type "file system" and see what turns up.

    Of course, you have to be judicious about this. Some people use this trick but aren't very careful about their search terms, and they end up sending questions to mailing lists like "Windows Team All" which are intended for announcements, not Q&A.

    You want to look for a feature-specific discussion group or Q&A group or bug reporting group, not an entire product group.

    Use your common sense.

    In many cases, you have an idea of a person who might be able to help you. You may know the name of somebody from the file system team because you see their name in status report mail, or you find their name in the change logs, or because they helped you out once before. But, of course, you don't want to go to that person directly, because that would be presumptuous, and they might be on vacation, or they might be busy, or they might not be the right person after all.

    But what you can do is look up their entry in the company Address Book, then click on Membership to see what mailing lists they belong to. Browse the list looking for something named "File system bugs" or "File system talk" or "File system automated testing failures" or "File system code reviews", depending on what sort of help you need. If you know more than one person who might help, you can do some set theory to narrow down on a good candidate mailing list to contact.

    (Within Microsoft, a common convention is for mailing lists that deal with general Q&A to have "talk" in their name, whereas those that deal with urgent issues have "hot" in their name. And then there is "casual" which is where team members hang out and discuss the latest episode of Breaking Bad Mad Men Game of Thrones.)

    Bonus chatter: There is a Microsoft internal Web site called Polyarchy which visualizes organizational data. One of the many things you can do is give it a list of people, and it will show you the mailing lists that they all belong to, thereby doing the set theory magic I alluded to earlier.

  • The Old New Thing

    Sorry for the interruption, but it doesn't happen often

    • 22 Comments

    Many years ago, my feature manager and I were called into the project leader's office for some reason or other, I forget exactly what.

    We were about five minutes into the meeting when the project leader's mobile phone rang. This was back in the days when mobile phones were not commonplace, and having one was a way of showing off your status.

    The project leader answered the call, but instead of saying, "I'm in a meeting, can I call you back?" he proceeded to carry on a conversation with the caller as if we weren't there, while we sat there and waited.

    I got up and left his office.

    I went downstairs to the lobby and read whatever newspaper happened to be sitting there for visitors to read while they waited. I think it was The Wall Street Journal, but it could have been The New York Times.

    After finishing a section of the paper, I came back upstairs to the project leader's office. By that time, the project leader had finished his call, whatever it was.

    As I sat down, the project leader said, "Sorry, I don't get calls on this phone often."

    I immediately replied, "That's okay, I don't read The Wall Street Journal often either."

  • The Old New Thing

    Reinterpreting the bits of a 64-bit integer as if they were a double-precision floating point number (and vice versa)

    • 22 Comments

    Today's Little Program takes a 64-bit integer and reinterprets its physical representation as a double-precision floating point number.

    using System;
    
    class Program
    {
     static double ReinterpretAsDouble(long longValue)
     {
      return BitConverter.ToDouble(BitConverter.GetBytes(longValue), 0);
     }
    
     static long ReinterpretAsLong(double doubleValue)
     {
      return BitConverter.ToInt64(BitConverter.GetBytes(doubleValue), 0);
     }
    
     static void Main()
     {
      Console.WriteLine(ReinterpretAsDouble(0x4000000000000000));
      Console.WriteLine("{0:X}", ReinterpretAsLong(2.0));
     }
    }
    

    Our first attempt uses the Bit­Converter class to convert the 64-bit integer to an array of bytes, and then parses a double-precision floating point number from that byte array.

    Maybe you're not happy that this creates a short-lived byte[] array that will need to be GC'd. So here's another version that is a little sneakier.

    using System;
    using System.Runtime.InteropServices;
    
    class Program
    {
     [StructLayout(LayoutKind.Explicit)]
     struct LongAndDouble
     {
      [FieldOffset(0)] public long longValue;
      [FieldOffset(0)] public double doubleValue;
     }
    
     static double ReinterpretAsDouble(long longValue)
     {
      LongAndDouble both;
      both.doubleValue = 0.0;
      both.longValue = longValue;
      return both.doubleValue;
     }
    
     static long ReinterpretAsLong(double doubleValue)
     {
      LongAndDouble both;
      both.longValue = 0;
      both.doubleValue = doubleValue;
      return both.longValue;
     }
     ...
    }
    

    This version creates a structure with an unusual layout: The two members occupy the same physical storage. The conversion is done by storing the 64-bit integer into that storage location, then reading the double-precision floating point value out.

    There's a third method that involves writing the 64-bit integer to a memory stream via Binary­Writer then reading it back with Binary­Reader, but this is clearly inferior to the Bit­Converter so I didn't bother writing it up.

    Update: Damien points out that this functionality already exists in the BCL: Bit­Converter.Double­To­Int64­Bits and Bit­Converter.Int64­Bits­To­Double. But there doesn't appear to be a Bit­Converter.Float­To­Int32­Bits method, so the techniques discussed above are not completely useless.

    Exercise: Why did I have to initialize the doubleValue before writing to longValue, and vice versa? What are the implications of the answer to the above question? (Yes, I could have written LongAndDouble both = new LongAndDouble();, which automatically zero-initializes everything, but then I wouldn't have had an interesting exercise!)

  • The Old New Thing

    Random links on taking better pictures

    • 28 Comments

    I'm always interested in finding simple things you can do to take better pictures. Here are some links I've collected.

    One thing I discovered as a tourist is that if you ask a random person to take your picture (because you're traveling alone or because it's a group picture), they will usually gladly oblige, but they will also do a really bad job of framing the photo.

    Here's what I want: A head-and-shoulders shot of me with the object of interest.


    Δ

    Usually I'll get this: The photographer has zoomed out because they want to get my whole body (and my sneakers and my backpack that I put on the ground because I don't want it in the picture):


    Δ
    ||
    ¯ ¯


    At least some cropping and zooming can undo that.

    Worse is when the photographer tries to fix the problem by taking a few steps back, thereby changing the relative sizes of the object and me.


    Δ
    ||
    ¯ ¯


    When you take a few steps back, I get smaller but the object of interest remains the same size (since it is further away).

    I've tried a few things, like taking a sample photo to show what I want. ("Just do this again, but I'll be standing there.") It usually doesn't help. The volunteer photographer will take the picture they want.

    I can't really complain, because they were doing me a favor. But I've also learned to set my expectations appropriately and assume that any picture not taken by me will not be framed in a manner I like.

    This upcoming Sunday is National Selfie Day, according to some DJ in Texas.

  • The Old New Thing

    Why does the class name for Explorer change depending on whether you open it with /e?

    • 21 Comments

    I noted some time ago that Explorer's original name was Cabinet, and that the name lingers in the programmatic class name: Cabinet­WClass. A commenter with a rude name points out that Explorer uses the class name Explorer­WClass if you open it with the /e command line switch, adding, "This is rather strange since you can toggle the folder pane on/off in the UI either way."

    In Windows 95, the window class names for Explorer were Cabinet­WClass for plain Explorer windows and Explorer­WClass for windows opened in Explore mode with the folder tree view thingie on the left hand side. This was not strange at the time because there were two different types of Explorer windows, and there was no way to change between them. The UI to toggle the folder pane on/off did not exist.

    Internally, the two types of Explorer windows were handled by different frame window classes, and naturally the two different classes got different names. The plain Explorer window frame hosted a view window, an address bar, and a status bar, whereas the fancy Explorer window frame hosted those components plus a folder tree. It wasn't until some time later that the ability to toggle the folder pane on and off was added. To do this, the two window classes were merged into a single implementation that dynamically added in or removed the folder tree.

    Great, we can get rid of Explorer­WClass and just use Cabinet­WClass for everything.

    And then the application compatibility bug reports came in.

    Because even though it wasn't documented, application relied on the implementation detail that plain Explorer windows could be found by doing a Find­Window for Cabinet­WClass, and that fancy Explorer windows could be found by doing a Find­Window for Explorer­WClass. They would do things like launch explorer.exe /e C:\some\folder, wait a few seconds, and then do a Find­Window("Explorer­WClass", ...) and expect to find a window. (Just do a Web search for Cabinet­WClass and Explorer­WClass if you don't believe me.)

    For compatibility, therefore, Explorer windows still use the old class names from Windows 95. If you open the window with the folder pane hidden, the class name is Cabinet­WClass, and if you open it with the folder pane visible, the class name is Explorer­WClass. The two classes are functionally identical, but people who rely on undocumented behavior expect to see the same names from 1995.

  • The Old New Thing

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

    • 40 Comments

    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
    Administrator
    Standard

    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
    Administrator
    Standard

    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

    • 18 Comments

    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\\*",
                                       FileExInfoBasic,
                                       &data,
                                       FindExSearchNameMatch,
                                       NULL,
                                       0);
    FindClose(hFindFile);
    
    RemoveDirectory(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

    • 16 Comments

    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

    Related.

  • The Old New Thing

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

    • 1 Comments

    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:

    void
    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,
                SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE);
              return;
            }
          }
          ...
    }
    

    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?

    • 14 Comments

    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.

Page 4 of 455 (4,548 items) «23456»