June, 2011

  • 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!

  • The Old New Thing

    In Windows, the directory is the application bundle

    • 70 Comments

    Aaargh! wonders why Windows doesn't just steal the concept of bundles from Apple and package up each application with all its libraries and everything else it needs into a single directory.

    This is such a great idea, it's been around since the early 1990's. It's just that Windows didn't give it a cute named like bundle. It just gave it the boring name directory. In other words, it's a victim of bad marketing. Maybe we should have given it a cute name like... elfgrass.

    The first directory searched by the LoadLibrary function is the directory containing the application. If you put all your supporting libraries in the same directory as your EXE, and if you access non-library data via paths relative to your application directory, then then you have successfully packaged up your application with all its libraries and everything else it needs into a single directory. Congratulations, you pre-invented the bundle.

    Indeed, Microsoft's guidance for over a decade has been to discourage copying files into the System32 directory.

    If this facility has been around for nearly twenty years, why do people still copy files into the System32 directory?

    Probably inertia. "We've always installed that way, and we're not changing it because we don't know what would stop working."

    There may be some people concerned about disk space. "We have a bunch of applications which share some common libraries, and by putting the common libraries in a shared location (instead of in the application directory), we avoid wasting the user's disk space." Which raises the troublesome question: Is disk space still an issue nowadays?

    Some people would say that no, disk space is no longer an issue. Hard drives are hundreds of gigabytes in size. Increasing the size of each application by a few dozen megabytes is just noise.

    Other people would say that yes, disk space is still an issue. (Note how many people got excited when Snow Leopard took up less disk space.) Solid-state hard drives are still limited in size, and even for people with large hard drives, you see them freaking out about the disk space used by things like Windows Update, volume snapshot services, and System Restore. (Nevermind that at least for volume snapshots and System Restore, the disk space is automatically released when disk space starts to run low. It's like getting upset that the disk cache uses so much of your memory even though the computer is not under any memory pressure.)

    Bonus reading: Disk space and Windows 7.

  • The Old New Thing

    How do I make a window remain visible even when the user selects Show Desktop?

    • 32 Comments

    A customer had this question:

    I'd like to know how to get a window to remain visible, even when the user has selected Show Desktop. Right now, when the user picks Show Desktop, the desktop appears and covers my window.

    Um, yeah, because that's the whole point of Show Desktop: To show the desktop and get rid of all those windows that are in the way. Windows like yours.

    We're sorry that Windows was unprepared for a program as awesome as yours, because there's no way to mark your window as even if the user says to show the desktop instead of this window, override the user's command and show the window anyway. (They're probably angling for a nice bonus.)

    As a consolation prize, you can create a desktop gadget. Desktop gadgets are part of the desktop and raise with it. It so happens that upon further discussion, the customer was trying to write a clock-type program—this is something very well-suited to gadgetification.

    A different customer had a related question, but disguised it behind another question:

    I noticed that desktop gadgets remain on the desktop even if the user clicks Show Desktop. How does that work? How do gadget stay in front of the desktop when it is shown? What is the trick?

    This was a rather odd question to come through the customer channel. And it probably wasn't just idle curiosity. You don't burn a support request for idle curiosity.

    (While it's probably true that you don't burn a support request just for idle curiosity, I've seen support requests turn into idle curiosity. Once the customers got the answer to their question, they realized that since they had already burned a support request, they may as well pile on with follow-up questions that are just idle curiosity. That was not the case here, because the customer led with the question.)

    The "trick" is that gadgets and the desktop know about each other, so when the user clicks Show Desktop, the desktop covers up all the windows on the screen and then takes the gadgets and places them on the desktop.

    The customer's question is rather odd, because they ask "The system works like X. Are there any tricks for X?" The answer is the rather tautological "The trick for how the system works like X is that the system was designed to do X."

    I suspect that the customer has a secret agenda they are unwilling to share. My guess is that their secret agenda is that they want to write a program that is exempt from being covered by the desktop when the user clicks Show Desktop, and they think they can do it by emulating whatever it is that gadgets do.

    The customer liaison confirmed that that's what the customer is actually trying to do, but that the customer was being coy with the liaison as well and did not explain what the problem scenario was that made them think that they needed a program that is exempt from being covered by the desktop when the user clicks Show Desktop. The customer liaison went back to the customer with the explanation that the way to get the special gadget behavior is to be a gadget, and if they want to pursue it, then writing a gadget is what they need to do.

  • The Old New Thing

    How do I create a right-aligned toolbar button?

    • 9 Comments

    I didn't think this was all that common a request, but it came in twice from two different customers, so I guess there are still people creating toolbars, and creating them with right-aligned buttons (even though it violates Windows user interface guidelines, though I can't find a citation right now).

    You may have noticed that the toolbar common control doesn't provide a facility for creating right-aligned buttons. Partly because it's a violation of the guidelines anyway, but mostly because the default state of every feature is "not implemented." Adding a feature requires work, and since there is only a finite amount of work available to apply, you have to decide where to spend it. And generally speaking, you don't focus your efforts on helping people violate the guidelines.

    If you want to create a right-aligned toolbar button, you can cobble one together by combining things you already have. I can think of two ways of doing this off the top of my head.

    • Create two toolbars, one for the left-aligned buttons and one for the right-aligned buttons, then size and position them appropriately.
    • Create a separator between the left-aligned buttons and the right-aligned buttons, and set the separator size appropriately.

    Which comes to a third reason why there is no feature for right-aligned toolbar buttons: Because you can already do it yourself without too much effort.

  • The Old New Thing

    How do I convert a UTF-8 string to UTF-16 while rejecting illegal sequences?

    • 11 Comments

    By default, when you ask Multi­Byte­To­Wide­Char to convert a UTF-8 string to UTF-16 that contains illegal sequences (such as overlong sequences), it will try to muddle through as best as it can. If you want it to treat illegal sequences as an error, pass the MB_ERR_INVALID_CHARS flag.

    The MSDN documentation on this subject is, to be honest, kind of hard to follow and even includes a double-negative: "The function does not drop illegal code points if the application does not set this flag." Not only is this confusing, it doesn't even say what happens to illegal code points when you omit this flag; all it says is what it doesn't do, namely that it doesn't drop them. Does it set them on fire? (Presumably, if you omit the flag, then it retains illegal code points, but how do you retain an illegal UTF-8 code point in UTF-16 output? It's like saying about a function like atoi "If the value cannot be represented as an integer, it is left unchanged." Huh? The function still has to return an integer. How do you return an unchanged string as an integer?)

  • The Old New Thing

    Sufficiently advanced magic is indistinguishable from technology

    • 12 Comments

    An informal tradition in a former group was that whenever somebody bought a new car, we all went out to lunch to celebrate, but the person with the new car had to be one of the drivers.

    During one of our new-car trips, the proud owner of the new car showed off its fancy features. "Check this out, this car has a voice-controlled radio: Radio, On."

    The car radio turned on.

    "Radio, Select KUOW."

    The radio changed its station.

    "Radio, louder."

    The volume went up.

    But this wasn't a demonstration of voice-recognition technology. It was a magic trick.

    You see, the car has radio controls built into the back of the steering wheel.

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

  • The Old New Thing

    You don't need to steal focus if you can just arrange for someone to give it to you

    • 18 Comments

    Commenter doesn't matter proposes a scenario where focus-stealing is necessary: There are two applications A and B, Application B exposes an interface, and Application A connects to application B via that interface, When some sort of even occurs in application B, it notifies application A, which wants to steal focus in order to interact with the user as a result of the event.

    Actually, this is still not a situation where focus-stealing is necessary. Application B just needs to call Allow­Set­Foreground­Window on application A before it fires the event, so that when application A receives the event, it can display its dialog box or whatever. If the communication channel is via a window message, you can use Get­Window­Thread­Process­Id to get the process ID of application A. If the communication channel is COM, you can use Co­Allow­Set­Foreground­Window. If the communication channel is something else, well, then you'll have to use whatever mechanism works for your communication channel. (Obviously there must be at some point a place in the communication channel where it can figure out the identity of application A, since it needs to talk to application A to deliver the event in the first place.)

    If you don't have access to the source code of application B, then you get to work with whoever designed the interface to convince them to add the necessary call for you.

    But outright stealing the focus is the wrong thing to do, because it presumes that the user was interacting with application B when the event was fired. What if the event fired while application B was not the focus? Even if the event is a user interface event, like a mouse click, it's possible that the event will fire even though application B doesn't have the focus: Application B may receive the mouse click, and while application B decides what to do with it, the user switches to application C. Eventually, application B fires the event, but at this point the user is no longer working with application B, and transfering focus to application A would count as one of those evil focus-stealing situations.

    Just because there's no good way to do something doesn't mean that you are automatically permitted to do it in a bad way.

    Bonus chatter: Sometimes I wonder about the people who use the principle If I can't do something legally, I should be allowed to do it illegally, and then get indignant when they are caught.

    "You got a parking ticket because you were parked in a handicapped space without a permit."

    But all the regular parking spaces were taken. I had to park in a handicapped space; I had no other choice. You can't give me a ticket for that!

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

  • The Old New Thing

    Generally speaking, if your function fails, you should return a failure code

    • 22 Comments

    A customer requested assistance with their shell namespace extension, and the request worked its way to me for resolution.

    Unhandled exception at 0x76fab89c (shell32.dll) in explorer.exe: 0xC0000005:
    Access violation reading location 0x00000000.
    
    shell32.dll!CShellItem::_GetPropertyStoreWorker()  + 0x44 bytes
    shell32.dll!CShellItem::GetPropertyStoreForKeys()  + 0x38 bytes
    thumbcache.dll!CThumbnailCache::_GetMonikerDataFromShellItem()  + 0x8b bytes
    thumbcache.dll!CThumbnailCache::GetThumbnail()  + 0x11c bytes
    shell32.dll!CSetOperationCallback::_LookupThumbnail()  + 0x8d bytes
    shell32.dll!CSetOperationCallback::_PrefetchCachedThumbnails()  + 0xb6 bytes
    shell32.dll!CSetOperationCallback::OnNextBatch()  + 0x4f bytes
    shell32.dll!CEnumTask::_PushBatchToView()  + 0x68 bytes
    shell32.dll!CEnumTask::_IncrFillEnumToView()  + 0x2ca5 bytes
    shell32.dll!CEnumTask::_IncrEnumFolder()  + 0x8da5a bytes
    shell32.dll!CEnumTask::InternalResumeRT()  + 0xa6 bytes
    shell32.dll!CRunnableTask::Run()  + 0x92 bytes
    browseui.dll!CShellTask::TT_Run()  + 0x2d bytes
    browseui.dll!CShellTaskThread::ThreadProc()  + 0x87 bytes
    browseui.dll!CShellTaskThread::s_ThreadProc()  + 0x21 bytes
    shlwapi.dll!_ExecuteWorkItemThreadProc@4()  + 0xe bytes
    ntdll.dll!_RtlpTpWorkCallback@8()  + 0xaa bytes
    ntdll.dll!_TppWorkerThread@4()  + 0x274 bytes
    kernel32.dll!@BaseThreadInitThunk@12()  + 0x12 bytes
    ntdll.dll!__RtlUserThreadStart@8()  + 0x27 bytes
    

    The customer was at a loss because the customer's code was nowhere on the stack. What is wrong?

    The customer didn't provide a dump file or any other information beyond the stack trace. (Hint: When reporting a problem with a shell namespace extension, at least mention the last few method calls your namespace extension received before the crash.) I was forced to use my psychic powers to solve the problem. But you can, too. All the information you need is right there in front of you.

    The shell faulted on a null pointer in the function CShellItem::_GetPropertyStoreWorker, which from its name is clearly a worker function which obtains the property store from a shell item.

    At this point, you put on your thinking cap. Why is the shell taking a null pointer fault trying to retrieve the property store from a shell item? Remember that the problem is tied to a custom namespace extension.

    My psychic powers tell me that the namespace extension returned S_OK from GetUIObjectOf(IPropertyStoreFactory) but set the output pointer to NULL.

    (It turns out my psychic powers were weak without coffee, because the initial psychic diagnosis was GetUIObjecttOf(IPropertyStore) instead of IPropertyStoreFactory.)

    As a general rule, if your function fails, then you should return a failure code, not a success code. There are exceptions to this rule, particular when OLE automation is involved, but it's a good rule to start with.

    The customer reported that fixing their IShellFolder::BindToObject to return an error code when it failed fixed the problem. The customer then followed up with another crash, again providing startling little information.

    Unhandled exception at 0x763cf7e7 (shell32.dll) in explorer.exe: 0xC0000005: 
    Access violation reading location 0x000a0d70.
    
    Call Stack:
    
    shell32.dll!CInfotipTask::InternalResumeRT() + 0x2e bytes 
    shell32.dll!CRunnableTask::Run() + 0x92 bytes 
    browseui.dll!CShellTask::TT_Run() + 0x2d bytes 
    browseui.dll!CShellTaskThread::ThreadProc() + 0x87 bytes 
    browseui.dll!CShellTaskThread::s_ThreadProc() + 0x21 bytes 
    shlwapi.dll!_ExecuteWorkItemThreadProc@4() + 0xe bytes 
    ntdll.dll!_RtlpTpWorkCallback@8() + 0xaa bytes 
    ntdll.dll!_TppWorkerThread@4() + 0x274 bytes 
    kernel32.dll!@BaseThreadInitThunk@12() + 0x12 bytes 
    ntdll.dll!__RtlUserThreadStart@8() + 0x27 bytes
    

    The customer reported that IQueryInfo::SetInfoTip is getting called. The customer liaison added, "Raymond, I'm looking forward to your psychic powers again."

    Apparently, some people don't understand that psychic powers are not something you ask for. It's my way of scolding you for not providing enough information to make a quality diagnosis possible. You don't come back saying, "Hey, thanks for answering my question even though I did a crappy job of asking it. Here's another crappy question!"

    I reported back that my psychic powers were growing weary from overuse, and that the customer might want to expend a little more time investigating the problem themselves. Especially since it has the same root cause as their previous problem.

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

  • The Old New Thing

    PE resources must be 4-byte aligned, but that doesn't stop people from trying other alignments

    • 38 Comments

    Resources in PE-format files must be stored at offsets which are a multiple of four. This requirement is necessary for platforms which are sensitive to data alignment.

    That doesn't stop people from breaking the rules anyway. After all, it sort of works anyway, as long as you're careful. I mean, sure maybe if somebody running a non-x86 version of Windows tries to read your resources, they will crash, but who uses non-x86 versions of Windows, right?

    In Windows Vista SP1, additional hardening was added to the resource parsing code to address various security issues, but the one that's important today is that tests were made to verify that the data were properly aligned before accessing it. This prevents a file with a misaligned version resource from crashing any program that tried to read its resources. In particular, it is common for programs to read the version resources of arbitrary files—for example, Explorer does it when you view the file's properties or if you turn on the Description column in Details view—so enforcing alignment on resources closes that avenue of remote denial of service.

    And then the bug reports came in. "Program XYZ fails to install" because the program tries to read its own version resources and cannot, because the tool they used to build the program cheated on the alignment requirement and stored the resources at offsets that aren't multiples of 4. "I mean, come on, that wastes like three bytes per resource. Everything still worked when we removed the alignment padding, so we went ahead and shipped it that way."

    Another example of a program that stopped working when the alignment rules were enforced was a computer game expansion pack which could not install because the code that tried to verify that you had the base game found itself unable to read its version resources.

    Multiple programs refused to run, preferring to display the error message "AppName is not a valid Win32 application." Presumably, as part of initialization, they tried to read their own version resources, which failed with ERROR_BAD_EXE_FORMAT, which they then showed to the user.

    The fix was to relax the enforcement of the rules back to the previous level, and impose the stricter requirements only on architectures which raise exceptions on misaligned data. It does mean that you can have a program whose resources can be read on one machine but not on the other, but that was deemed a lesser evil than breaking all the programs which relied on being able to misalign their data without consequence.

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

  • The Old New Thing

    Microspeak: The planned unplanned outage, and other operations jargon

    • 22 Comments

    The Operations group at Microsoft manage the servers which keep the company running. And they have their own jargon which is puzzling to those of us who don't spend all our days in a noisy server room.

    • Unplanned Unplanned Outage
    • Planned Unplanned Outage
    • Immediate Deployment Timeframe. This one even has its own TLA: IDT.

    From what I can gather, an Unplanned Outage would be better termed an Unscheduled Outage: We did not have it marked off on our calendar that the server would be unavailable at this time, but it ended up that way. These unscheduled outages fall into two categories: An Unplanned Unplanned Outage is an unscheduled outage that took place of its own volition. In other words, the server crashed or somebody accidentally kicked the power cable. On the other hand, the paradoxically-named Planned Unplanned Outage is an unscheduled outage that took place because the operations team took the server down out of schedule. For example, the server may have started thrashing, and they think rebooting it will help.

    But the one that sounds really Microspeaky is Immediate Deployment Timeframe. Here's a citation:

    Date: June 7, 2011 4:52 PM

    ...
    Due to the critical nature of this issue, the hotfix will be deployed in an Immediate Deployment Timeframe. All affected servers will be remediated on June 8.

    Start: June 7, 2011 11:00PM
    End: June 8, 2011 12:00AM

    In other word, Immediate Deployment Timeframe means as soon as possible. Note, however that it doesn't mean now, which is what I originally thought immediate meant until I looked at the start/end times and compared them to the message time. There must be some other TLA that means now, but what is faster than immediate?

    Bonus Microspeak: remediate.

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

Page 2 of 3 (25 items) 123