• The Old New Thing

    2008 Q1 link clearance: Microsoft blogger edition

    • 12 Comments
  • The Old New Thing

    2007 year-end link clearance

    • 5 Comments

    A few random links that I've collected over the last six months.

    And then the obligatory plug for my column in TechNet Magazine, which, despite the fact that Microsoft's name is on the magazine cover, does not establish the official Microsoft position on anything.

  • The Old New Thing

    Don't be helpless: You can put things together, it doesn't have to be a single command

    • 29 Comments

    Humans are distinguished among all animal species by their advanced development of and heavy reliance on tools. Don't betray your ancestors. Use those tools you have.

    For example, during the debugging of a thread pool problem, it looked like somebody did a PostThreadMessage to a thread pool thread and left the message unprocessed after the thread pool function returned. Who could it have been? Well, one idea was to see if there were any DLLs in the system which called both QueueUserWorkItem and PostThreadMessage.

    I did a little legwork and contributed the following analysis to the mail thread:

    Of all the DLLs loaded into the process, the following call PostThreadMessage:

    SHLWAPI.dll 77D72436 221 PostThreadMessageA
    SHELL32.dll 77D78596 222 PostThreadMessageW
    ole32.dll 77D78596 222 PostThreadMessageW
    ... (list trimmed; you get the idea) ...

    Of those DLLs, these also call QueueUserWorkItem:

    shlwapi.dll
    shell32.dll
    ... (list trimmed; you get the idea) ...

    Astounded, somebody wanted to know how I came up with that list.

    Nothing magic. You have the tools, you have a brain, so connect the dots.

    The lm debugger command lists all the DLLs loaded into the process. Copy the output from the debugger window and paste it into a text file. Now write a little script that takes each line of the text file and does a link /dump /imports on the corresponding DLL. I happen to prefer perl for this sort of thing, but you can use a boring batch file if you like.

    for /f %i in (dlls.txt) do ^
    @echo %i & link /dump /imports %i | findstr PostThreadMessage
    

    Scrape the results off the screen, prune out the misses, and there you have it.

    "I tried that, but the result wasn't in the same format as what you posted."

    Well, yeah. There's no law that says that I can't manually reformat the data before presenting it in an email message. Since there were only a dozen hits, it's not worth writing a script to do that type of data munging. Typing "backspace, home, up-arrow" twelve times is a lot faster than writing a script to take the output of the above batch file and turn it into the output I used in the email message.

    Another boring batch file filters the list to those DLLs that also call QueueUserWorkItem. Writing it (or a script in your favorite language) is left as an exercise.

    No rocket science here. Just taking a bunch of tools and putting them together to solve a problem. That's what your brain is for, after all.

  • The Old New Thing

    If you pin a program, it doesn't show up in the frequently-used programs list

    • 18 Comments

    After the initial explorations with the Windows XP Start menu, we had to add a rule that fine-tuned the results: If a program is pinned, then it is removed from consideration as a frequently-used program.

    For example, if you right-click Lotus Notes and select "Pin to Start menu", then it goes into the pin list and will never show up in the dynamic portion of the front page of the Start menu. This tweak was added to avoid the ugly situation where you have two icons for the same program on the front page of the Start menu, when only one would do the job.

    This is another manifestation of the "Don't show me something I already know" principle, which we saw earlier when we discussed why the All Programs list doesn't use Intellimenus. After all, you pinned the program to your Start menu because you run it often. There's no point in showing it again at the top of your "frequently-used" list; you knew that already! Use that scarce real estate to show the user something that is actually of value.

    Next time, another fine-tuning rule that tries to filter the noise from the results.

  • The Old New Thing

    How can I find all objects of a particular type?

    • 28 Comments

    More than one customer has asked a question like this:

    I'm looking for a way to search for all instances of a particular type at runtime. My goal is to invoke a particular method on each of those instances. Note that I did not create these object myself or have any other access to them. Is this possible?

    Imagine what the world would be like if it were possible.

    For starters, just imagine the fun you could have if you could call typeof(Secure­String).Get­Instances(). Vegas road trip!

    More generally, it breaks the semantics of App­Domain boundaries, since grabbing all instances of a type lets you get objects from another App­Domain, which fundamentally violates the point of App­Domains. (Okay, you could repair this by saying that the Get­Instances method only returns objects from the current App­Domain.)

    This imaginary Get­Instances method might return objects which are awaiting finalization, which violates one of the fundamental assumptions of a finalizer, namely that there are no references to the object: If there were, then it wouldn't be finalized! (Okay, you could repair this by saying that the Get­Instances method does not return objects which are awaiting finalization.)

    On top of that, you break the syncRoot pattern.

    class Sample {
     private object syncRoot = new object();
     public void Method() {
      lock(syncRoot) { ... };
     }
    }
    
    If it were possible to get all objects of a particular class, then anybody could just reach in and grab your private sync­Root and call Monitor.Enter() on it. Congratuations, the private synchronization object you created is now a public one that anybody can screw with, defeating the whole purpose of having a private syncRoot. You can no longer reason about your syncRoot because you are no longer in full control of it. (Yes, this can already be done with reflection, but at least when reflecting, you know that you're grabbing somebody's private field called sync­Root, so you already recognize that you're doing something dubious. Whereas with Get­Instances, you don't know what each of the returned objects is being used for. Heck, you don't even know if it's being used! It might just be garbage lying around waiting to be collected.)

    More generally, code is often written on the expectation that an object that you never give out a reference to is not accessible to others. Consider the following code fragment:

    using (StreamWriter sr = new StreamWriter(fileName)) {
     sr.WriteLine("Hello");
    }
    

    If it were possible to get all objects of a particular class, you may find that your customers report that they are getting an Object­Disposed­Exception on the call to Write­Line. How is that possible? The disposal doesn't happen until the close-brace, right? Is there a bug in the CLR where it's disposing an object too soon?

    Nope, what happened is that some other thread did exactly what the customer was asking for a way to do: It grabbed all existing Stream­Writer instances and invoked Stream­Writer.Close on them. It did this immediately after you constructed the Stream­Writer and before you did your sr.Write­Line(). Result: When your sr.Write­Line() executes, it finds that the stream was already closed, and therefore the write fails.

    More generally, consider the graffiti you could inject into all output files by doing

    foreach (StreamWriter sr in typeof(StreamWriter).GetInstances()) {
     sr.Write("Kilroy was here!");
    }
    

    or even crazier

    foreach (StringBuilder rb in typeof(StringBuilder).GetInstances()) {
     sb.Insert(0, "DROP TABLE users; --");
    }
    

    Now no String­Builder is safe—the contents of any String­Builder can be corrupted at any time!

    If you could obtain all instances of a type, the fundamental logic behind computer programming breaks down. It effectively becomes impossible to reason about code because anything could happen to your objects at any time.

    If you need to be able to get all instances of a class, you need to add that functionality to the class itself. (GC­Handle or Weak­Reference will come in handy here.) Of course, if you do this, then you clearly opted into the "anything can happen to your object at any time outside your control" model and presumably your code operates accordingly. You made your bed; now you get to lie in it.

    (And I haven't even touched on thread safety.)

    Bonus reading: Questionable value of SyncRoot on Collections.

  • The Old New Thing

    Actually, FlagsAttribute can't do more; that's why it's an attribute

    • 27 Comments

    A few years ago, Abhinaba wondered why FlagsAttribute didn't also alter the way enumeration values are auto-assigned.

    Because attributes don't change the language. They are instructions to the runtime environment or (in rarer cases) to the compiler. An attribute can instruct the runtime environment to treat the function or class in a particular way. For example, you can use an attribute to tell the runtime environment that you want the program entry point to run in a single-threaded apartment, to tell the runtime environment how to look up your p/invoke function, or to tell the compiler to suppress a particular class of warnings.

    But changing how values for enumerations are assigned, well that actually changes the language. An attribute can't change the operator precedence tables. An attribute can't change the way overloaded functions are resolved. An attribute can't change the statement block tokens from curly braces to square braces. An attribute can't change the IL that gets generated. The code still compiles to the same IL; the attribute just controls the execution environment, such as how the JIT compiler chooses to lay out a structure in memory.

    Attribute or not, enumerations follow the same rule for automatic assignment: An enumeration symbol receives the value one greater than the previous enumeration symbol.

  • The Old New Thing

    Sensor development kits were flying off the shelves

    • 21 Comments

    After the Sensor and Location Platform PDC presentation, people were stopping by the booth and grabbing sensor hardware and development kits like they were candy. Then again, to geeks, this stuff is candy.

    (And technically, they weren't flying off shelves. They were flying out of bins. Well, and technically they weren't flying either.)

    Other notes from the last day of the 2008 PDC:

    • PDC content honcho Mike Swanson announced that PDC 2008 sessions and keynotes are now up for download, and will be available indefinitely. Available in Silverlight for live streaming, or in iTunes format, WMV, high-quality WMV (this one includes video of the speakers), and Zune for offline viewing. In response, Nigel Parker created the PDC session firehose.
    • Sometimes, when you make the sign too big, nobody can see it. Someone came up to me asking where the Azure booth was. I pointed at the insanely huge banner. "Probably somewhere over there."
    • The reason why room 406A is on the third floor but you press 2 to get there: The room numbers at the convention center are numbered based on room clusters. The 100's in one cluster, the 400's are in another cluster, etc. The "4" in 406 doesn't mean fourth floor; it means fourth cluster. And why do you push 2 to get to the third floor? Because Level 1 is a split level which occupies two floors. Therefore, in the elevator, there are two buttons to get to Level 1, depending on whether you want the upper half or lower half. Cluster 4 is on Level 2, so the button for that is 3.
    • A video of carrots. If you had come to my PDC talk, you'd understand. (The carrot joke elicited a mild chuckle from the main room, but I'm told that in the overflow room it totally killed. I'm not sure what that says about people in the overflow room. It really wasn't that great a joke, people.)
    • At Ask the Experts, I started out at one of the Windows 7 tables, and we speculated as to what the most obscure technical question would be. One of my colleagues suggested that it would be a BitLocker question. And what would you know, the very first person to come to our table had a BitLocker question. Later in the evening, I moved to another Windows 7 table and posed the same question. At the second table, we figured that the most obscure technical question would be about the dispatcher spinlock. About fifteen minutes later, somebody stopped by with a question about the dispatcher spinlock. I decided to stop playing this game. It was too much like a Twilight Zone episode.
    • One attendee was shy about speaking English (not being a native speaker) and came up with a clever solution: The attendee walked up to our table, said, "I have some questions, can you read them?" and then opened a laptop computer where a Word document awaited with the four questions already typed up in a large font so everybody could read them. We answered the questions, and everybody seemed pleasantly surprised with how well this approach worked.
    • At the end of the conference the Channel 9 folks held a giveaway for their giant beanbags. Like anybody would be able to take a giant beanbag home on the airplane. (Second prize: Two beanbags!)
    • James Senior has the PDC by the numbers. I have trouble believing the number of bananas consumed, though. Twenty-five bananas in four days? Perhaps we should start calling James Monkey Boy.
  • The Old New Thing

    Common gotchas when writing your own p/invoke

    • 21 Comments

    If you're looking to get into some p/invoke action, you'd be well-served to check out the pinvoke wiki to see if somebody else has done it too. If what you need isn't there, you may end up forced to write your own, and here are some gotchas I've seen people run into:

    • C++ bool and Win32 BOOLEAN are not the same as C# bool (aka System.Boolean). In Win32, BOOL is a 4-byte type, and BOOLEAN is a 1-byte type. [See also MadQ's remarks about VARIANT_BOOL.] Meanwhile, C++ bool is not standardized by Win32, so the size will vary based on your compiler, but most compilers use a 1-byte value. And then C# is even weirder: The bool is a 1-byte type, but it marshals as a 4-byte type by default.
    • Win32 char is not the same as C# char (aka System.Char). In C#, char is a Unicode character (two bytes), whereas in C/C++ under Win32 it is an ANSI character (one byte).
    • Win32 long is not the same as C# long (aka System.Int64). In C#, long is 64-bit value, whereas in C/C++ under Win32 it is a 32-bit value.
    • If memory is allocated and freed across the interop boundary, make sure both sides are using the same allocator. It is my understanding that the CLR uses CoTaskMemAlloc/CoTaskMemFree by default. If your Win32 function doesn't use CoTaskMemAlloc, you'll have to teach the CLR which allocator you really want.
    • When laying out structures, you have to watch out for alignment.

    That last one is particularly gnarly on 64-bit systems, where alignment requirements are less forgiving than on x86. The structure declarations on pinvoke.net tend to ignore 64-bit issues. For example, the declaration of the INPUT structure (as of this writing—it's a wiki so it's probably changed by the time you read this) reads as follows:

    [StructLayout(LayoutKind.Explicit)]struct INPUT {
      [FieldOffset(0)] int type;
      [FieldOffset(4)] MOUSEINPUT mi;
      [FieldOffset(4)] KEYBDINPUT ki;
      [FieldOffset(4)] HARDWAREINPUT hi;
    }
    

    This structure layout is correct for 32-bit Windows, but it's incorrect for 64-bit Windows.

    Let's take a look at that MOUSEINPUT structure, for starters.

    typedef struct tagMOUSEINPUT {
        LONG    dx;
        LONG    dy;
        DWORD   mouseData;
        DWORD   dwFlags;
        DWORD   time;
        ULONG_PTR dwExtraInfo;
    } MOUSEINPUT, *PMOUSEINPUT, FAR* LPMOUSEINPUT;
    

    In 64-bit Windows, the LONG and DWORD members are four bytes, but the dwExtraInfo is a ULONG_PTR, which is eight bytes on a 64-bit machine. Since Windows assumes /Zp8 packing, the dwExtraInfo must be aligned on an 8-byte boundary, which forces four bytes of padding to be inserted after the time to get the dwExtraInfo to align properly. And in order for all this to work, the MOUSEINPUT structure itself must be 8-byte aligned.

    Now let's look at that INPUT structure again. Since the MOUSEINPUT comes after the type, there also needs to be padding between the type and the MOUSEINPUT to get the MOUSEINPUT back to an 8-byte boundary. In other words, the offset of mi in the INPUT structure is 8 on 64-bit Windows, not 4.

    Here's how I would've written it:

    // This generates the anonymous union
    [StructLayout(LayoutKind.Explicit)] struct INPUT_UNION {
      [FieldOffset(0)] MOUSEINPUT mi;
      [FieldOffset(0)] KEYBDINPUT ki;
      [FieldOffset(0)] HARDWAREINPUT hi;
    };
    
    [StructLayout(LayoutKind.Sequential)] struct INPUT {
      int type;
      INPUT_UNION u;
    }
    

    I introduce a helper structure to represent the anonymous union that is the second half of the Win32 INPUT structure. By doing it this way, I let somebody else worry about the alignment, and it'll be correct for both 32-bit and 64-bit Windows.

    static public void Main()
    {
      Console.WriteLine(Marshal.OffsetOf(typeof(INPUT), "u"));
    }
    

    On a 32-bit system, this prints 4, and on a 64-bit system, it prints 8. The downside is that you have to type an extra u. when you access the mi, ki or hi members.

    input i;
    i.u.mi.dx = 0;
    

    (I haven't checked what the PInvoke Interop Assistant comes up with for the INPUT structure.)

  • The Old New Thing

    Points are earned by programs, not by shortcuts

    • 63 Comments

    The first subtlety of the basic principle that determines which programs show up in the Start menu is something you may not have noticed when I stated it:

    Each time you launch a program, it "earns a point", and the longer you don't launch a program, the more points it loses.

    Notice that the rule talks about programs, not shortcuts.

    The "points" for a program are tallied from all the shortcuts that exist on the All Programs section of the Start menu. Many programs install multiple shortcuts, say one to the root of the All Programs menu and another to a deep folder. It doesn't matter how many shortcuts you have; if they all point to the same program, then it is that program that earns the points when you use any of the shortcuts.

    One the Start menu decides that a program has earned enough points to make it to the front page, it then has to choose which shortcut to use to represent that program. This is an easy decision if there's only one shortcut. If there are multiple shortcuts to the same program, then the most-frequently-used shortcut is selected as the one to appear on the front page of the Start menu.

    If you paid really close attention, you may have noticed a subtlety to this subtlety. We'll take that up next time.

    Please hold off your questions until the (two-week!) series is complete, because I suspect a later entry will answer them. (This series is an expansion upon the TechNet column on the same topic. If you've read the TechNet article, then a lot of this series will be review.)*

    Footnotes

    *I wrote this last time, but that didn't stop people from asking questions anyway. I don't expect it'll work today either, but who knows, maybe you'll surprise me.

  • The Old New Thing

    The program doesn't have to be run from the Start menu to earn Start menu points

    • 29 Comments

    There's a second subtlety to the basic principle that determines which programs show up in the Start menu:

    Each time you launch a program, it "earns a point", and the longer you don't launch a program, the more points it loses.

    Since programs earn points and not shortcuts, a program can earn points even if you don't use the Start menu to run it.

    In usability studies, we often see people who run programs by digging through their Program Files directory until they find an icon that looks promising and then double-click it. If there is a shortcut on the All Programs section of the Start menu that points to the same program, then that shortcut will eventually work its way onto the front page, assuming the user runs the program often enough.

    This is why you will see a program appear on the front page of the Start menu even though you never ran it from the Start menu. The program earned points because you ran the program manually, or because you opened a document that is associated with that program. Promoting a program run this way helps users realize that they can run Backgammon from the Start menu instead of having to open My Computer, then click on my C drive, then click on Program Files, then MSN Gaming Zone, then Windows, and then double-click the icon with the strange name bckgzm. I've seen usability sessions where the users did this repeatedly, and they considered it perfectly normal, albeit frustrating. "Computers are so hard to use."

    Next time, we'll look at how the pin list influences the list of frequently-used programs.

Page 8 of 434 (4,335 items) «678910»