Quantcast
Channel: The Old New Thing
Viewing all 3085 articles
Browse latest View live

Like a chicken talking to a duck

0
0

Many years ago, I called the home of my Chinese-speaking nieces. This was before they started learning English and before I started learning their dialect of Chinese. After the call was over, the eldest niece asked, "Who was that on the phone?"

"That was Uncle Raymond."

"Oh, I want to talk to Uncle Raymond!"

Her mother replied, "That'd be like a chicken talking to a duck."

A chicken talking to a duck is a Chinese idiom referring to two people who cannot communicate due to a language barrier.

It seems that ducks are somehow central to the concept of language unintelligibility. Is there a duck-related language idiom in your language?


Why don't the file timestamps on an extracted file match the ones stored in the ZIP file?

0
0

A customer liaison had the following question:

My customer has ZIP files stored on a remote server being accessed from a machine running Windows Server 2003 and Internet Explorer Enhanced Security Configuration. When we extract files from the ZIP file, the last-modified time is set to the current time rather than the time specified in the ZIP file. The problem goes away if we disable Enhanced Security Configuration or if we add the remote server to our Trusted Sites list. We think the reason is that if the file is in a non-trusted zone, the ZIP file is copied to a temporary location and is extracted from there, and somehow the date information is lost.

The customer is reluctant to turn off Enhanced Security Configuration (which is understandable) and doesn't want to add the server as a trusted site (somewhat less understandable). Their questions are

  • Why is the time stamp changed during the extract? If we copy the ZIP file locally and extract from there, the time stamp is preserved.
  • Why does being in an untrusted zone affect the behavior?
  • How can we avoid this behavior without having to disable Enhanced Security Configuration or adding the server as a trusted site?

The customer has an interesting theory (that the ZIP file is copied locally) but it's the wrong theory. After all, copying the ZIP file locally doesn't modify the timestamps stored inside it.

Since the ZIP file is on an untrusted source, a zone identifier is being applied to the extracted file to indicate that the resulting file is not trustworthy. This permits Explorer to display a dialog box that says "Do you want to run this file? It was downloaded from the Internet, and bad guys hang out there, bad guys who try to give you candy."

And that's why the last-modified time is the current date: Applying the zone identifier to the extracted file modifies its last-modified time, since the file on disk is not identical to the one in the ZIP file. (The one on disk has the "Oh no, this file came from a stranger with candy!" label on it.)

The recommended solution is to add the server containing trusted ZIP files to your trusted sites list. Since the customer is reluctant to do this (for unspecified reasons), there are some other alternatives, though they are considerably riskier. (These alternatives are spelled out in KB article 883260: Description of how the Attachment Manager works.)

You can disable the saving of zone information from the Group Policy Editor, under Administrative Templates, Windows Components, Attachment Manager, Do not preserve zone information in file attachments. This does mean that users will not be warned when they attempt to use a file downloaded from an untrusted source, so you have to trust your users not to execute that random executable they downloaded from some untrusted corner of the Internet.

You can use the Inclusion list for low, moderate, and high risk file types policy to add ZIP as a low-risk file type. This is not quite as drastic as suppressing zone information for all files, but it means that users who fall for the "Please unpack the attached ZIP file and open the XYZ icon" trick will not receive a "Do you want to eat this candy that a stranger gave to you?" warning prompt before they get pwned.

But like I said, it's probably best to add just the server containing the trusted ZIP files to your trusted sites list. If the server contains both trusted and untrusted data (maybe that's why the customer doesn't want to put it on the trusted sites list), then you need to separate the trusted data from the untrusted data and put only the trusted server's name in your trusted sites list.

Your program loads libraries by their short name and you don't even realize it

0
0

In the discussion of the problems that occur if you load the same DLL by both its short and long names, Xepol asserted that any program which loads a DLL by its short name "would have ONLY itself to blame for making stupid, unpredictable, asinine assumptions" and that Windows should "change the loader to NOT load any dll with a short name where the short name and long name do not match."

The problem with this rule, well, okay, one problem is that you're changing the rules after the game has started. Programs have been allowed to load DLLs by their short name in the past; making it no longer possible creates an application compatibility hurdle.

Second, it may not be possible to obtain the long name for a DLL. If the user has access to the DLL but not to one of the directories in the path to the DLL, then the attempt to get its long name will fail. The "directory you can access hidden inside a directory you cannot access" directory structure is commonly used as a less expensive alternative to Access Based Enumeration. Maybe your answer to this is to say that this is not allowed; people who set up their systems this way deserve to lose.

Third, the application often does not control the path being passed to Load­Library, so it doesn't even know that it's making a stupid, unpredictable, asinine assumption. For example, the program may call Get­Module­File­Name to obtain the directory the application was installed to, then attempt to load satellite DLLs from that same directory. If the current directory was set by passing a short name to Set­Current­Directory (try it: cd C:\Progra~1) then the program will unwittingly be making a stupid, unpredictable, asinine decision. (But since the decision is being made consistently, there was no problem up until now.)

When you call Co­Create­Instance, there is nearly always a Load­Library happening behind the scenes, because the object you are trying to create is coming from a DLL that somebody else registered. If they registered it with a short name, then any application that wanted to use that object runs afoul of the new rule, even though the application did nothing wrong.

Now, you might argue that this just means that the component provider is the one who made a stupid, unpredicable, asinine assumption. But that may not have been a stupid assumption at the time: 16-bit applications see only short names, so it might have been that that's the only thing they can do. Or the component may have made a conscious decision to register under short names; this was common in the Windows 95 era because file names often passed through components that didn't understand long file names. (Examples: 16-bit applications, backup applications.)

Even if you decide that what was once a reasonable decision is now asinine, you have to get there from here. Do you declare all 16-bit applications asinine (because they can only use those asinine short file name)? Even for the 32-bit components, how do you convince them to switch over? Can you even get them to switch over? Until they do, their component will not be accessible: The shell extension won't be loaded until they fix their registration. A program which anticipated this problem and always loaded DLLs by their short names is now broken. (After all, you had to make an arbitrary decision to use long names exclusively or short names exclusively, and someone may have chosen the other branch of the decision tree.)

And long name/short name is really just a special case of a single file having multiple names. Other ways of creating multiple names include hard links, symbolic links, and junction points. If a file has two names due to hard links, which one is the "preferred" name and which is the "asinine" name? (And what if the "preferred" name is not available to the user? Suppose you decide that the preferred name is the one that comes first alphabetically. Can I launch a denial-of-service attack by creating a hard link to C:\Windows\system32\shell32.dll called C:\A\A.DLL? All attempts to link to C:\Windows\system32\shell32.dll will fail because it is now the "asinine" name.) Does this rule against loading DLLs by "asinine" names negate part of the functionality of the compatibility paths introduced in Windows Vista (since, under this new rule, you can't use them to load DLLs or execute programs because they entail traversing a symbolic link).

Perhaps these concerns could be addressed in a manner that didn't have all these problems, but it's an awful lot of complexity. In general, simple rules are preferred to complex rules. Especially if the complexity is to address an issue that was not a serious problem to begin with.

A function pointer cast is a bug waiting to happen

0
0

A customer reported an application compatibility bug in Windows.

We have some code that manages a Win32 button control. During button creation, we subclass the window by calling Set­Window­Subclass. On the previous version of Windows, the subclass procedure receives the following messages, in order:

  • WM_WINDOWPOSCHANGING
  • WM_NCCALCSIZE
  • WM_WINDOWPOSCHANGED

We do not handle any of these messages and pass them through to Def­Subclass­Proc. On the latest version of Windows, we get only the first two messages, and comctl32 crashes while it's handling the third message before it gets a chance to call us. It looks like it's reading from invalid memory.

The callback function goes like this:

LRESULT ButtonSubclassProc(
    HWND hwnd,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam,
    UINT_PTR idSubclass,
    DWORD_PTR dwRefData);

We install the subclass function like this:

SetWindowSubclass(
    hwndButton,
    reinterpret_cast<SUBCLASSPROC>(ButtonSubclassProc),
    id,
    reinterpret_cast<DWORD_PTR>(pInfo));

We found that if we changed the callback function declaration to

LRESULT CALLBACK ButtonSubclassProc(
    HWND hwnd,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam,
    UINT_PTR idSubclass,
    DWORD_PTR dwRefData);

and install the subclass function like this:

SetWindowSubclass(
    hwndButton,
    ButtonSubclassProc,
    id,
    reinterpret_cast<DWORD_PTR>(pInfo));

then the problem goes away. It looks like the new version of Windows introduced a compatibility bug; the old code works fine on all previous versions of Windows.

Actually, you had the problem on earlier versions of Windows, too. You were just lucky that the bug wasn't a crashing bug. But now it is.

This is a classic case of mismatching the calling convention. The SUB­CLASS­PROC function is declared as requiring the CALLBACK calling convention (which on x86 maps to __stdcall), but the code declared it without any calling convention at all, and the ambient calling convention was __cdecl. When they went to compile the code, they got a compiler error that said something like this:

error C2664: 'SetWindowSubclass' : cannot convert parameter 2 from 'LRESULT (__cdecl *)(HWND,UINT,WPARAM,LPARAM,UINT_PTR,DWORD_PTR)' to 'SUBCLASSPROC'

"Since the compiler was unable to convert the parameter, let's give it some help and stick a cast in front. There, that shut up the compiler. Those compiler guys are so stupid. They can't even figure out how to convert one function pointer to another. I bet they need help wiping their butts when they go to the bathroom."

And there you go, you inserted a cast to shut up the compiler and masked a bug instead of fixing it.

The only thing you can do with a function pointer after casting it is to cast it back to its original type.¹ If you try to use it as the cast type, you will crash. Maybe not today, maybe not tomorrow, but someday.

In this case, the calling convention mismatch resulted in the stack being mismatched when the function returns. It looks like earlier versions of Windows managed to hobble along long enough before things got resynchronized (by an EBP frame restoration, most likely) so the damage didn't spread very far. But the new version of Windows, possibly one compiled with more aggressive optimizations, ran into trouble before things resynchronized, and thus occurred the crash.

The compiler was yelling at you for a reason.

It so happened that the Windows application compatibility team had already encountered this problem in their test labs, and a shim had already been developed to auto-correct this mistake. (Actually, the shim also corrects another mistake they hadn't noticed yet: They forgot to call Remove­Window­Subclass when they were done.)

¹I refer here to pointers to static functions. Pointers to member functions are entirely different animals.

Sorting is a state and a verb (and a floor wax and a dessert topping)

0
0

Cliff Barbier points out that after you sort an Explorer view by name, new items are not inserted in their sorted position. This goes back to the question of whether sorting is a state or a verb.

If you take an Explorer folder and say Sort by Name, do you mean "From now on, always show the contents of this folder sorted by name"? Or do you mean "Rearrange the items currently in this folder so they are sorted by name"? The first case treats sorting a state, where sorting is an attribute of the folder that persists. The second case treats sorting as a verb, where the action is performed so that its effects linger but the action itself is not remembered.

You might think that sorting is obviously a state, but STL disagrees with you:

std::vector<Item> v;
... fill v with stuff ...
std::sort(v.begin(), v.end(), Item::ByName);
v.push_back(Item(...));

When the last line of code appends a new item to the vector, it is not inserted in sorted order because std::sort is a verb which acts on the vector, not a state of the vector itself. The vector doesn't know "Oh, wait, I'm now a sorted vector."

Okay, so in Explorer, is sorting a state or a verb?

"Let's do both!"

Sorting is a state, in the sense that the list of items is presented in sorted order when the folder. It's a verb in that the sorted order is not maintained when new items are added to the view while the folder is open.

Placing new items at the end instead of in their sorted position is necessary to avoid having items move around unbidden. Suppose you're looking at a folder sorted by name, you scroll down the list, find the item you want, and just as your finger is posed to click the mouse button, another process creates a file in the folder, which Explorer picks up and inserts into the view, causing the items to shift, and when your finger goes down on the mouse button, you end up clicking on the wrong item.

You can imagine how annoying this can end up when there is a lot of file creation activity in the folder. If the items in the view were continuously sorted, then they would keep moving around and make it impossible to click on anything!

Mind you, you do have this instability problem when files are deleted and you are in a non-placed view (like List or Details), but there's at least a cap on how much trouble deletion can cause (since eventually you delete all the items that were in the view originally).

It looks like starting in Windows Vista, Explorer tries to insert new items into their sorted position, so at least in the modern versions of Windows, sort is a state. Good luck trying to click on something when the contents of the folder are constantly changing.

Why is hybrid sleep off by default on laptops? (and how do I turn it on?)

0
0

Hybrid sleep is a type of sleep state that combines sleep and hibernate. When you put the computer into a hybrid sleep state, it writes out all its RAM to the hard drive (just like a hibernate), and then goes into a low power state that keeps RAM refreshed (just like a sleep). The idea is that you can resume the computer quickly from sleep, but if there is a power failure or some other catastrophe, you can still restore the computer from hibernation.

A hybrid sleep can be converted to a hibernation by simply turning off the power. By comparison, a normal sleep requires resuming the computer to full power in order to write out the hibernation file. Back in the Windows XP days, I would sometimes see the computer in the next room spontaneously turn itself on: I'm startled at first, but then I see on the screen that the system is hibernating, and I understand what's going on.

Hybrid sleep is on by default for desktop systems but off by default on laptops. Why this choice?

First of all, desktops are at higher risk of the power outage scenario wherein a loss of power (either due to a genuine power outage or simply unplugging the computer by mistake) causes all work in progress to be lost. Desktop computers typically don't have a backup battery, so a loss of power means instant loss of sleep state. By comparison, laptop computers have a battery which can bridge across power outages.

Furthermore, laptops have a safety against battery drain: When battery power gets dangerously low, it can perform an emergency hibernate.

Laptop manufacturers also requested that hybrid sleep be off by default. They didn't want the hard drive to be active for a long time while the system is suspending, because when users suspend a laptop, it's often in the form of "Close the lid, pick up the laptop from the desk, throw it into a bag, head out." Performing large quantities of disk I/O at a moment when the computer is physically being jostled around increases the risk that one of those I/O's will go bad. This pattern doesn't exist for desktops: When you suspend a desktop computer, you just leave it there and let it do its thing.

Of course, you can override this default easily from the Control Panel. Under Power Options, select Change plan settings, then Changed advanced power settings, and wander over into the Sleep section of the configuration tree.

If you're a command line sort of person, you can use this insanely geeky command line to enable hybrid sleep when running on AC power in Balanced mode:

powercfg -setacvalueindex 381b4222-f694-41f0-9685-ff5bb260df2e
                          238c9fa8-0aad-41ed-83f4-97be242c8f20
                          94ac6d29-73ce-41a6-809f-6363ba21b47e 1

(All one line. Take a deep breath.)

Okay, what do all these insane options mean?

-setacvalueindex sets the behavior when running on AC power. To change the behavior when running on battery, use -setdcvalueindex instead. Okay, that was easy.

The next part is a GUID, specifically, the GUID that represents the balanced power scheme. If you want to modify the setting for a different power scheme, then substitute that scheme's GUID.

After the scheme GUID comes the subgroup GUID. Here, we give the GUID for the Sleep subgroup.

Next we have the GUID for the Hybrid Sleep setting.

Finally, we have the desired new value for the setting. As you might expect, 1 enables it and 0 disables it.

And where did these magic GUIDs come from? Run the powercfg -aliases command to see all the GUIDs. You can also run powercfg -q to view all the settings and their current values in the current power scheme.

Bonus reading:

Why double-null-terminated strings instead of an array of pointers to strings?

0
0

I mentioned this in passing in my description of the format of double-null-terminated strings, but I think it deserves calling out.

Double-null-terminated strings may be difficult to create and modify, but they are very easy to serialize: You just write out the bytes as a blob. This property is very convenient when you have to copy around the list of strings: Transferring the strings is a simply memory of transferring the memory block as-is. No conversion is necessary. This makes it easy to do things like wrap the memory inside another container that supports only flat blobs of memory.

As it turns out, a flat blob of memory is convenient in many ways. You can copy it around with memcpy. (This is important when doing capturing values across security boundaries.) You can save it to a file or into the registry as-is. It marshals very easily. It becomes possible to store it in an IData­Object. It can be freed with a single call. And in the cases where you can't allocate any memory at all (e.g., you're filling a buffer provided by the caller), it's one of the few options available. This is also why self-relative security descriptors are so popular in Windows: Unlike absolute security descriptors, self-relative security descriptors can be passed around as binary blobs, which makes them easy to marshal, especially if you need to pass one from kernel mode to user mode.

A single memory block with an array of integers containing offsets would also work, but as the commenter noted, it's even more cumbersome than double-null-terminated strings.

Mind you, if you don't need to marshal the list of strings (because it never crosses a security boundary and never needs to be serialized), then an array of string pointers works just fine. If you look around Win32, you'll find that most cases where double-null terminated strings exist are for the most part either inherited from 16-bit Windows or are one of the cases where marshalling is necessary.

Looking at the world through kernel-colored glasses

0
0

During a discussion of the proper way of cancelling I/O, the question was raised as to whether it was safe to free the I/O buffer, close the event handle, and free the OVERLAPPED structure immediately after the call to CancelIo. The response from the kernel developer was telling.

That's fine. We write back to the buffer under a try/except, so if the memory is freed, we'll just ignore it. And we take a reference to the handle, so closing it does no harm.

These may be the right answers from a kernel-mode point of view (where the focus is on ensuring that consistency in kernel mode is not compromised), but they are horrible answers from an application point of view: Kernel mode will write back to the buffer and the OVERLAPPED when the I/O completes, thereby corrupting user-mode memory if user-mode had re-used the memory for some other purpose. And if the handle in the OVERLAPPED structure is closed, then user mode has lost its only way of determining when it's safe to continue! You had to look beyond the literal answer to see what the consequences were for application correctness.

(You can also spot the kernel-mode point of view in the clause "if the memory is freed." The developer is talking about freed from kernel mode's point of view, meaning that it has beed freed back to the operating system and is no longer committed in the process address space. But memory that is logically freed from the application's point of view may not be freed back to the kernel. It's usually just freed back into the heap's free pool.)

The correct answer is that you have to wait for the I/O to complete before you free the buffer, close the event handle, or free the OVERLAPPED structure.

Don't fall into this trap. The kernel developer was looking at the world through kernel-colored glasses. But you need to look at the situation from the perspective of your customers. When the kernel developer wrote "That's fine", he meant "That's fine for me." Sucks to be you, though.

It's like programming an autopilot to land an airplane, but sending it through aerobatics that kill all the passengers. If you ask the autopilot team, they would say that they accomplished their mission: Technically, the autopilot did land the airplane.

Here's another example of kernel-colored glasses. And another.

Epilogue: To be fair, after I pointed out the kernel-mode bias in the response, the kernel developer admitted, "You're right, sorry. I was too focused on the kernel-mode perspective and wasn't looking at the bigger picture."


If undecorated names are given in the DLL export table, why does link /dump /exports show me decorated names?

0
0

If you run the link /dump /exports command on a DLL which exports only undecorated names, you may find that in addition to showing those undecorated names, it also shows the fully-decorated names.

We're building a DLL and for some functions, we have chosen to suppress the names from the export table by using the NONAME keyword. When we dump the exports, we still see the names. And the functions which we did want to export by name are showing up with their decorated names even though we list them in the DEF file with undecorated names. Where is the decorated name coming from? Is it being stored in the DLL after all?

        1        00004F1D [NONAME] _Function1@4
        2        000078EF [NONAME] _Function2@12
        3        00009063 [NONAME] _Function3@8

The original decorated names are not stored in the DLL. The link /dump /exports command is sneaky and looks for a matching PDB file and, if finds one, extracts the decorated names from there.

(How did I know this? I didn't, but I traced each file accessed by the link /dump /exports command and observed that it went looking for the PDB.)

Multithreaded UI code may be just as hard as multithreaded non-UI code, but the consequences are different

0
0

Commenter Tim Smith claims that the problems with multithreaded UI code are not significantly more than plain multithreaded code. While that may be true on a theoretical level, the situations are quite different in practice.

Regardless of whether your multithreaded code does UI or not, you have to deal with race conditions, synchronization, cache coherency, priority inversion, all that mulitthreaded stuff.

The difference is that multithreaded problems with non-UI code are often rare, relying on race conditions and other timing issues. As a result, you can often get away with a multithreaded bug, because it may shows up in practice only rarely, if ever. (On the other hand, when it does show up, it's often impossible to diagnose.)

If you mess up multithreaded UI code, the most common effect is a hang. The nice thing about this is that it's easier to diagnose because everything has stopped and you can try to figure out who is waiting for what. On the other hand, the problems also occur with much more frequency.

So it's true that the problems are the same, but the way they manifest themselves are very different.

Why does Explorer show a thumbnail for my image that's different from the image?

0
0

A customer (via a customer liaison) reported that Explorer somestimes showed a thumbnail for an image file that didn't exactly match the image itself.

I have an image that consists of a collage of other images. When I switch Explorer to Extra Large Icons mode, the thumbnail is a miniature representation of the image file. But in Large Icons and Medium Icons mode, the thumbnail image shows only one of the images in the collage. I've tried deleting the thumbnail cache, but that didn't help; Explorer still shows the wrong thumbnails for the smaller icon modes. What is wrong?

The customer provided screenshots demonstrating the problem, but the customer did not provide the image files themselves that were exhibiting the problem. I therefore was reduced to using my psychic powers.

My psychic powers tell me that your JPG file has the single-item image as the camera-provided thumbnail. The shell will use the camera-provided thumbnail if suitable.

The customer liaison replied,

The customer tells me that the problem began happening after they edited the images. Attached is one of the images that's demonstrating the problem.

Some image types (most notable TIFF and JPEG) support the EXIF format for encoding image metadata. This metadata includes information such as the model of camera used to take the picture, the date the picture was taken, and various camera settings related to the photograph. But the one that's interesting today is the image thumbnail.

When Explorer wants to display a thumbnail for an image, it first checks whether the image comes with a precalculated thumbnail. If so, and the thumbnail is at least as large as the thumbnail Explorer wants to show, then Explorer will use the image-provided thumbnail instead of creating its own from scratch. If the thumbnail embeded in the image is wrong, then when Explorer displays the image-provided thumbnail, the result will be incorrect. Explorer has no idea that the image is lying to it.

Note that the decision whether to use the image-provided thumbnail is not based solely on the view. (In other words, the conclusion is not "Explorer uses the image-provided thumbnail for Large Icons and Medium Icons but ignores it for Extra Large Icons.) The decision is based on both the view and the size of the image-provided thumbnail. If the image-provided thumbnail is at least the size of the view, then Explorer will use it. For example, if your view is set to 64 × 64 thumbnails, then the image-provided thumbnail will be used if it is at least 64 × 64.

The Wikipedia page on EXIF points out that "Photo manipulation software sometimes fails to update the embedded information after an editing operation." It appears that some major image editing software packages fail to update the EXIF thumbnail when an image is edited, which can result in inadvertent information disclosure: If the image was cropped or otherwise altered to remove information, the information may still linger in the thumbnail. This Web site has a small gallery of examples.

How long do taskbar notification balloons appear on the screen?

0
0

We saw some time ago that taskbar notification balloons don't penalize you for being away from the computer. But how long does the balloon stay up when the user is there?

Originally, the balloon appeared for whatever amount of time the application specified in the uTimeout member of the NOTIFYICONDATA structure, subject to a system-imposed minimum of 10 seconds and maximum of 60 seconds.

In Windows XP, some animation was added to the balloon, adding 2 seconds of fade-in and fade-out animation to the display time.

Starting in Windows Vista, applications are no longer allowed to specify how long they wanted the balloon to appear; the uTimeout member is ignored. Instead, the display time is the amount of time specified by the SPI_GETMESSAGEDURATION system parameter, with 1 second devoted to fade-in and 5 seconds devoted to fade-out, with a minimum of 3 seconds of full visibility. In other words, if you set the message duration to less than 1+3+5=9 seconds, the taskbar behaves as if you had set it to 9 seconds.

The default message duration is 5 seconds, so in fact most systems are in the "shorted possible time" case. If you want to extend the time for which balloons notification appear, you can use the SystemParametersInfo function to change it:

BOOL SetMessageDuration(DWORD seconds, UINT flags)
{
 return SystemParametersInfo(SPI_SETMESSAGEDURATION,
                             0, IntToPtr(seconds), flags);
}

(You typically don't need to mess with this setting, because you can rescue a balloon from fading out by moving the mouse over it.)

Note that an application can also set the NIF_REALTIME flag, which means "If I can't display the balloon right now, then just skip it."

Watching the battle between Facebook and Facebook spammers

0
0

I am watching the continuing battle between Facebook and Facebook spammers with detached amusement. When I see a spam link posted to a friend's Facebook wall, I like to go and figure out how they got fooled. Internet Explorer's InPrivate Browsing comes in handy here, because I can switch to InPrivate mode before visiting the site, so that the site can't actually cause any harm to my Facebook account since I'm not logged in and it doesn't know how to log me in.

The early versions were simply Web pages that hosted an embedded YouTube video, but they placed an invisible "Like" button over the playback controls, so that any attempt to play the video resulted in a Like being posted to your wall.

Another early version of Facebook spam pages sent you to a page with an embedded YouTube video, but they also ran script that monitored your mouse position and positioned a 1×1 pixel Like button under it. That way, no matter where you clicked, you clicked on the Like button.

A more recent variant is one that displayed a simple math problem and asked you to enter the answer. The excuse for this is that it is to "slow down robots", but really, that answer box is a disguised Facebook comment box. You can see the people who fell for this because their Facebook wall consists of a link to the page with the comment "7".

My favorite one is a spam page that said, "In order to see the video, copy this text and paste it into your Address bar." The text was, of course, some script that injected code into the page so it could run around sending messages to all your Facebook friends. The kicker was that the script being injected was called owned.js. (The spam was so unsophisticated, it made you copy the text yourself! Not like this one which puts the attack string on your clipboard automatically.)

I started to think, "Who could possibly fall for this?" And then I realized that the answer is "There will always be people who will fall for this." These are the people who would fall for the honor system virus.

Update: On May 20, I saw a new variant. This one puts up a fake Youtube [sic] "security" dialog that says, "To comply with our Anti-SPAM™ regulations for a safe internet experience we are required to verify your identity" by solving a CAPTCHA. (This makes no sense.) The words in the CAPTCHA by an amazing coincidence happen to be a comment somebody might make on a hot video. Because the alleged CAPTCHA dialog is a disguised Facebook comment box. The result is that the victim posts a comment like "so awesome" to their own wall, thereby propagating the spam.

Why is my program terminating with exit code 3?

0
0

There is no standard for process exit codes. You can pass anything you want to Exit­Process, and that's what Get­Exit­Code­Process will give back. The kernel does no interpretation of the value. If youw want code 42 to mean "Something infinitely improbable has occurred" then more power to you.

There is a convention, however, that an exit code of zero means success (though what constitutes "success" is left to the discretion of the author of the program) and a nonzero exit code means failure (again, with details left to the discretion of the programmer). Often, higher values for the exit code indicate more severe types of failure. The command processor ERROR­LEVEL keyword was designed with these convention in mind.

There are cases where your process will get in such a bad state that a component will take it upon itself to terminate the process. For example, if a process cannot locate the DLLs it imports from, or one of those DLLs fails to initialize, the loader will terminate the process and use the status code as the process exit code. I believe that when a program crashes due to an unhandled exception, the exception code is used as the exit code.

A customer was seeing their program crash with an exit code of 3 and couldn't figure out where it was coming from. They never use that exit code in their program. Eventually, the source of the magic number 3 was identified: The C runtime abort function terminates the process with exit code 3.

BeginBufferedPaint: It's not just for buffered painting any more

0
0

I covered the BeginBufferedPaint function in my 2008 PDC presentation, but one thing I didn't mention is that the buffered paint functions are very handy even if you have no intention of painting.

Since the buffered paint functions maintain a cache (provided that you remembed to call Buffered­Paint­Init), you can use Begin­Buffered­Paint to get a temporary bitmap even if you have no intention of actually painting to the screen. You might want a bitmap to do some off-screen composition, or for some other temporary purpose, in which case you can ask Begin­Buffered­Paint to give you a bitmap, use the bitmap for whatever you like, and then pass fUpdateTarget = FALSE when you call End­Buffered­Paint to say "Ha ha, just kidding."

One thing to have to be aware of is that the bitmap provided by Begin­Buffered­Paint is not guaranteed to be exactly the size you requested; it only promises that the bitmap will be at least the size you requested. Most of the time, your code won't care (there are just pixels out there that you aren't using), but if you use the Get­Buffered­Paint­Bits function to obtain direct access to the bits, don't forget to take the stride into account.

Consider this artifical example of a program that uses Create­DIB­Section to create a temporary 32bpp bitmap for the purpose of updating a layered window. Start with the scratch program and make these changes:
BOOL
OnCreate(HWND hwnd, LPCREATESTRUCT lpcs)
{
 BOOL fRc = FALSE;
 HDC hdcWin = GetDC(hwnd);
 if (hdcWin) {
  HDC hdcMem = CreateCompatibleDC(hdcWin);
  if (hdcMem) {
   const int cx = 200;
   const int cy = 200;
   RECT rc = { 0, 0, cx, cy };
   BITMAPINFO bmi = { 0 };
   bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
   bmi.bmiHeader.biWidth = cx;
   bmi.bmiHeader.biHeight = cy;
   bmi.bmiHeader.biPlanes = 1;
   bmi.bmiHeader.biBitCount = 32;
   bmi.bmiHeader.biCompression = BI_RGB;
   RGBQUAD *prgbBits;
   HBITMAP hbm = CreateDIBSection(hdcWin, &bmi,
             DIB_RGB_COLORS, &reinterpret_cast<void*&>(prgbBits),
                                                        NULL, 0);
   if (hbm) {
    HBITMAP hbmPrev = SelectBitmap(hdcMem, hbm);

    // Draw a simple picture
    FillRect(hdcMem, &rc,
                     reinterpret_cast<HBRUSH>(COLOR_INFOBK + 1));
    rc.left = cx / 4;
    rc.right -= rc.left;
    rc.top = cy / 4;
    rc.bottom -= rc.top;
    FillRect(hdcMem, &rc,
                   reinterpret_cast<HBRUSH>(COLOR_INFOTEXT + 1));

    // Apply the alpha channel (and premultiply)
    for (int y = 0; y < cy; y++) {
     for (int x = 0; x < cx; x++) {
      RGBQUAD *prgb = &prgbBits[y * cx + x];
      BYTE bAlpha = static_cast<BYTE>(cx * x / cx);
      prgb->rgbRed = static_cast<BYTE>(prgb->rgbRed * bAlpha / 255);
      prgb->rgbBlue = static_cast<BYTE>(prgb->rgbBlue * bAlpha / 255);
      prgb->rgbGreen = static_cast<BYTE>(prgb->rgbGreen * bAlpha / 255);
      prgb->rgbReserved = bAlpha;
     }
    }

    // update the layered window
    POINT ptZero = { 0, 0 };
    SIZE siz = { cx, cy };
    BLENDFUNCTION bf =  { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
    fRc = UpdateLayeredWindow(hwnd, NULL, &ptZero, &siz, hdcMem,
                              &ptZero, 0, &bf, ULW_ALPHA);
    SelectBitmap(hdcMem, hbmPrev);
    DeleteObject(hbm);
   }
   DeleteDC(hdcMem);
  }
  ReleaseDC(hwnd, hdcWin);
 }
 return fRc;
}

Pretty standard stuff. But let's convert this to use the buffered paint functions to take advantage of the buffered paint bitmap cache.

BOOL
OnCreate(HWND hwnd, LPCREATESTRUCT lpcs)
{
 BOOL fRc = FALSE;
 HDC hdcWin = GetDC(hwnd);
 if (hdcWin) {
  HDC hdcMem;
  // HDC hdcMem = CreateCompatibleDC(hdcWin);
  // if (hdcMem) {
   const int cx = 200;
   const int cy = 200;
   RECT rc = { 0, 0, cx, cy };
   // BITMAPINFO bmi = { 0 };
   // bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
   // bmi.bmiHeader.biWidth = cx;
   // bmi.bmiHeader.biHeight = cy;
   // bmi.bmiHeader.biPlanes = 1;
   // bmi.bmiHeader.biBitCount = 32;
   // bmi.bmiHeader.biCompression = BI_RGB;
   RGBQUAD *prgbBits;
   BP_PAINTPARAMS params = { sizeof(params), BPPF_NOCLIP };
   HPAINTBUFFER hbp = BeginBufferedPaint(hdcWin, &rc,
                              BPBF_TOPDOWNDIB, &params, &hdcMem);
   if (hbp) {
    int cxRow;
    if (SUCCEEDED(GetBufferedPaintBits(hpb, &prgbBits, &cxRow))) {
   // HBITMAP hbm = CreateDIBSection(hdcWin, &bmi,
   //        DIB_RGB_COLORS, &reinterpret_cast<void*&>(prgbBits),
   //                                                   NULL, 0);
   // if (hbm) {
    // HBITMAP hbmPrev = SelectBitmap(hdcMem, hbm);

    // Draw a simple picture
    FillRect(hdcMem, &rc,
                     reinterpret_cast<HBRUSH>(COLOR_INFOBK + 1));
    rc.left = cx / 4;
    rc.right -= rc.left;
    rc.top = cy / 4;
    rc.bottom -= rc.top;
    FillRect(hdcMem, &rc,
                   reinterpret_cast<HBRUSH>(COLOR_INFOTEXT + 1));

    // Apply the alpha channel (and premultiply)
    for (int y = 0; y < cy; y++) {
     for (int x = 0; x < cx; x++) {
      RGBQUAD *prgb = &prgbBits[y * cxRow + x];
      BYTE bAlpha = static_cast<BYTE>(cx * x / cx);
      prgb->rgbRed = static_cast<BYTE>(prgb->rgbRed * bAlpha / 255);
      prgb->rgbBlue = static_cast<BYTE>(prgb->rgbBlue * bAlpha / 255);
      prgb->rgbGreen = static_cast<BYTE>(prgb->rgbGreen * bAlpha / 255);
      prgb->rgbReserved = bAlpha;
     }
    }

    // update the layered window
    POINT ptZero = { 0, 0 };
    SIZE siz = { cx, cy };
    BLENDFUNCTION bf =  { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
    fRc = UpdateLayeredWindow(hwnd, NULL, &ptZero, &siz, hdcMem,
                              &ptZero, 0, &bf, ULW_ALPHA);
    // SelectBitmap(hdcMem, hbmPrev);
    // DeleteObject(hbm);
   }
   EndBufferedPaint(hpb, FALSE);
   // DeleteDC(hdcMem);
  }
  ReleaseDC(hwnd, hdcWin);
 }
 return fRc;
}

// changes to WinMain
 if (SUCCEEDED(BufferedPaintInit())) {
 // if (SUCCEEDED(CoInitialize(NULL))) {/* In case we use COM */
  hwnd = CreateWindowEx(WS_EX_LAYERED,
  // hwnd = CreateWindow(
  ...
  BufferedPaintUnInit();
  // CoUninitialize();
  ...

We're using the buffered paint API not for buffered painting but just as a convenient way to get a bitmap and a DC at one shot. It saves some typing (you don't have to create the bitmap and the DC and select the bitmap in and out), and when you return the paint buffer to the cache, some other window that calls Begin­Buffered­Paint may be able to re-use that bitmap.

There are a few tricky parts here. First, if you're going to be accessing the bits directly, you need to call Get­Buffered­Paint­Bits and use the cxRow to determine the bitmap stride. Next, when we're done, we pass FALSE to End­Buffered­Paint to say, "Yeah, um, thanks for the bitmap, but don't Bit­Blt the results back into the DC we passed to Begin­Buffered­Paint. Sorry for the confusion."

A less obvious trick is that we used BPPF_NOCLIP to get a full bitmap. By default, Begin­Buffered­Paint returns you a bitmap which is clipped to the DC you pass as the first parameter. This is an optimization to avoid allocating memory for pixels that can't be seen anyway when End­Buffered­Paint goes to copy the bits back to the original DC. We don't want this optimization, however, since we have no intention of blitting the results back to the original DC. The clip region of the original DC is irrelevant to us because we just want a temporary bitmap for some internal calculations.

Anyway, there you have it, an example of using Begin­Buffered­Paint to obtain a temporary bitmap. It doesn't win much in this example (since we call it only once, at window creation time), but if you have code which creates a lot of DIB sections for temporary use, you can use this trick to take advantage of the buffered paint cache and reduce the overhead of bitmap creation and deletion.

Pre-emptive snarky comment: "How dare you show us an alternative method that isn't available on Windows 2000!"


One engineer's interpretation of the Segway as a hybrid vehicle

0
0

In a discussion of commuting options (in which I was primarily an observer), the following exchange took place:

A: I would rather get kicked in the shins every morning than bike up the massive hill that sits between my apartment and main campus.

B: Have you tried an electric bike?

C: If you're going to eliminate pedaling, then you may as well go all the way and get a Segway.

B: Actually, I used to own a Segway. I was floored by the engineering achievement of creating a device that combined the speed benefits of walking with the exercise benefits of driving, and for just the cost of a used Honda!

Note, of course, that this is just one engineer's opinion. Some people at Microsoft are quite enamored of the Segway device.

Public Service Announcement: Today is Bike to Work Day. A number of commute stations will be set up along popular bike routes in the greater Seattle area to hand out bicycling information and snacks. And if you pass a guy creeping up the 520 hill at around 8:00am, that was probably me. Sorry I forgot to wave.

If it's possible to do something, then it's possible to do something WRONG

0
0

Once you make it possible to do something, you have to accept that you also made it possible to do something wrong.

When the window manager was originally designed, it made it possible for programs to override many standard behaviors. They could handle the WM_NC­HIT­TEST message so a window can be dragged by grabbing any part of the window, not just the caption bar. They could handle the WM_NC­PAINT message to draw custom title bars. The theory was that making all of these things possible permitted smart people to do clever things.

The downside is that it also permits stupid people to do dumb things.

Changing the window procedure model from call Def­Window­Proc to get default behavior to return whether you handled the message wouldn't have helped. First of all, the handled/not-handled model is too restrictive: It requires you to do everything (handled) or nothing (not handled). There is no option to do a little bit. (Imagine if C++ didn't let you call the base class implementation of an overridden method.)

Doing a little bit is a very common pattern. The WM_NC­HITTEST technique mentioned above, for example, uses the default hit-testing implementation, and then tweaks the result slightly:

case WM_NCHITTEST:
 // call base class first
 lres = DefWindowProc(hwnd, uMsg, wParam, lParam);
 // tweak the result
 if (lres == HTCLIENT) lres = HTCAPTION;
 return lres;

How would you do this with the handled/not-handled model?

case WM_NCHITTEST:
 if (not handling this message would have resulted in HTCLIENT) {
  lres = HTCAPTION;
  handled = TRUE;
 } else {
  handled = FALSE;
 }
 break;

The trick about that bit in parentheses is that it requires the research department to finish the final details on that time machine they've been working on. It's basically saying, "Return not handled, then follow the message until handling is complete and if the final result is HTCLIENT, then fire up the time machine and rewind to this point so I can change my mind and return handled instead."

And even if the research department comes through with that time machine, the handled/not-handled model doesn't even solve the original problem!

The original problem was people failing to call Def­Window­Proc when they decided that they didn't want to handle a message. In the handled/not-handled model, the equivalent problem would be people returning handled = TRUE unconditionally.

BOOL NewStyleWindowProc(HWND hwnd, UINT uMsg,
 WPARAM wParam, LPARAM lParam, LRESULT& lres)
{
 BOOL handled = TRUE;
 switch (uMsg) {
 case WM_THIS: ...; break;
 case WM_THAT: ...; break;
 // no "default: handled = FALSE; break;"
 }
 return handled;
}

(Side note: The dialog manager uses the handled/not-handled model, and some people would prefer that it use the Def­Xxx­Proc model, so you might say "We tried that, and some people didn't like it.")

This topic raises another one of those "No matter what you do, somebody will call you an idiot" dilemmas. On the one side, there's the Windows should perform extra testing at runtime to detect bad applications school, and on the other side, there's the Windows should get rid of all the code whose sole purpose in life is to detect bad applications school.

Microspeak: PowerPoint Karaoke and the eye chart

0
0

The game PowerPoint-Karaoke was invented in 2006 by Zentrale Ingelligenz Agentur. In this game, contestants are called upon to give a PowerPoint presentation based on a slide deck they have never seen. (The German spelling uses a hyphen between the two words. When "translated" into English, the hyphen is often omitted.)

At Microsoft, the term has been extended to refer to giving a presentation from slides prepared by somebody else, usually on short notice and therefore with little preparation.

Bob is out sick today, so I'll be giving the overview. Sorry for the PowerPoint Karaoke.

This is shorthand for "Sorry if this presentation is a bit clumsy, but I'm stepping in on short notice, and I'm not completely familiar with this slide deck."

In the context of PowerPoint presentations, an eye chart is a slide so dense with text that reading it is a test of visual acuity. The term is usually used as part of an apology for having created such a horrible slide in the first place.

More generally, the term eye chart refers to any presentation of data in a ridiculously small font. For example, over in the sales/marketing part of Microsoft, there are spreadsheets with titles like FY05 Sales Forecast Eye Chart. Here's what one of them might look like:

Region Jul 2005   Aug 2005   Sep 2005   Q1   Oct 2005   Nov 2005   Dec 2005   Q2 ...
FY05 Fcst FY04 Y-Y FY05 Fcst FY04 Y-Y FY05 Fcst FY04 Y-Y FY05 Fcst FY04 Y-Y FY05 Fcst FY04 Y-Y FY05 Fcst FY04 Y-Y FY05 Fcst FY04 Y-Y FY05 Fcst FY04 Y-Y
Northeast Widgets 57 57 0% 74 61 22% 85 92 −8% 216 209 3% 71 70 2% 53 59 −11% 90 89 1% 215 218 −2%
Doodads 41 52 −22% 79 81 −3% 100 85 18% 219 218 1% 49 52 −7% 93 84 12% 87 79 10% 229 214 7%
Gizmos 64 55 16% 95 88 7% 56 67 −16% 215 211 2% 59 79 −25% 58 69 −16% 68 83 −18% 186 231 −20%
Northeast Total 159 157 2% 138 168 −18% 170 212 −20% 467 537 −13% 205 224 −8% 209 177 18% 194 244 −21% 608 645 −6%
Southeast Widgets 80 70 15% 75 82 -8% 57 60 -5% 212 212 0% 63 83 -24% 49 53 -8% 92 75 23% 204 211 -3%
Doodads 59 69 -14% 60 73 -17% 67 68 -1% 187 210 -11% 54 70 -23% 98 86 14% 58 50 16% 210 206 2%
Gizmos 75 89 -15% 59 61 -3% 124 100 24% 259 250 3% 80 89 -10% 84 96 -13% 40 52 -23% 204 237 -14%
Southeast Total 204 239 -15% 220 189 17% 151 187 -19% 576 615 -6% 172 175 -2% 168 210 -20% 122 152 -20% 462 538 -14%
... etc for about a bajillion more rows ...

(The abbreviation Y-Y is being used correctly for once. Writing the program to generate all this fake data took far, far longer than writing the rest of this posting! It got a lot easier once I realized that, since this is just fake data, the totals don't have to add up.)

Giving the spreadsheet the title Eye Chart lets people know that this is the spreadsheet crammed with data to the point of information overload. If that's what you're looking for.

I wouldn't be surprised if these uses of the terms PowerPoint Karaoke and eye chart are also popular at other companies.

Bonus chatter: Last year, I was asked to give a repeat of a presentation I hadn't given in several months. I had only a little bit of time to prepare, and there were times where I lost my place and had to refer to my notes (which I thankfully remembered to keep). It's embarrassing to find yourself playing PowerPoint Karaoke to your own slide deck.

WinMain is just the conventional name for the Win32 process entry point

0
0

WinMain is the conventional name for the user-provided entry point in a Win32 program. Just like in 16-bit Windows, where the complicated entry point requirements were converted by language-provided startup code into a call to the the user's WinMain function, the language startup code for 32-bit programs also does the work of converting the raw entry point into something that calls WinMain (or wWinMain or main or _wmain).

The raw entry point for 32-bit Windows applications has a much simpler interface than the crazy 16-bit entry point:

DWORD CALLBACK RawEntryPoint(void);

The operating system calls the function with no parameters, and the return value (if the function ever returns) is passed to the ExitThread function. In other words, the operating system calls your entry point like this:

...
  ExitThread(RawEntryPoint());
  /*NOTREACHED*/

Where do the parameters to WinMain come from, if they aren't passed to the raw entry point?

The language startup code gets them by asking the operating system. The instance handle for the executable comes from GetModuleHandle(NULL), the command line comes from GetCommandLine, and the nCmdShow comes from GetStartupInfo. (As we saw before, the hPrevInstance is always NULL.)

If you want to be hard-core, you can program to the raw entry point. Mind you, other parts of your program may rely upon the work that the language startup code did before calling your WinMain. For example, the C++ language startup code will run global constructors before calling into WinMain, and both C and C++ will initialze the so-called security cookie used as part of stack buffer overrun detection. Bypass the language startup code at your peril.

Bonus chatter: Notice that if you choose to return from your entry point function, the operating system passes the return value to ExitThread and not ExitProcess. For this reason, you typically don't want to return from your raw entry point but instead want to call ExitProcess directly. Otherwise, if there are background threads hanging around, they will prevent your process from exiting.

How do IsThemeActive, IsAppThemed, and IsCompositionActive differ?

0
0

There are three functions which test very similar things, and sometimes applications pick the wrong one. Here's the rundown:

  • IsThemeActive checks whether visual styles are enabled for the user. This is not an application-specific setting; it tells you whether visual styles are enabled in general. Note that this does not tell you whether the current application is using visual styles.
  • IsAppThemed checks whether visual styles are enabled for the current application. Windows may disable visual styles for a specific application (even though they are enabled in general) for compatiblity reasons.
  • IsCompositionActive checks whether desktop composition is enabled for the current application. As with visual styles, Windows may disable desktop composition for a specific application (even though it is enabled in general) for compatiblity reasons.
Note that these functions do not answer the question "Is the application using the visual-styles-enabled version of the common controls library?" That question is harder to answer because the decision to use the visual-styles-enabled version of the common controls library is not a process-wide one but is rather made on a window-by-window basis. You can have an application where half of the button controls are the old non-visual-styles version and half of the button controls participate in visual styles. (You may have seen this in action in Explorer, where the OK button on the Run dialog participates in visual styles, yet a button in a shell extension does not.)

How can you tell whether a particular button is an old-school button or a fancy new button? I don't know either.

Viewing all 3085 articles
Browse latest View live




Latest Images