November, 2004

  • The Old New Thing

    What's the difference between GetKeyState and GetAsyncKeyState?

    • 14 Comments

    I've seen some confusion over the difference between the GetKeyState function and the GetAsyncKeyState function.

    GetKeyState returns the virtual key state. In other words, GetKeyState reports the state of the keyboard based on the messages you have retrieved from your input queue. This is not the same as the physical keyboard state:

    • If the user has typed ahead, GetKeyState doesn't report those changes until you use the PeekMessage function or the GetMessage function to retrieve the message from your input queue.

    • If the user has switched to another program, then the GetKeyState function will not see the input that the user typed into that other program, since that input was not sent to your input queue.

    When should you use GetKeyState and when should you use GetAsyncKeyState?

    For user interface work, you nearly always want GetKeyState.

    If you are responding to an input message and want to know what keys were pressed at the time that input was generated, then you want to use GetKeyState. For example, if you want to distinguish a left-click of the mouse from an Alt+LeftClick, you must use GetKeyState to query the state of the Alt key (known as VK_MENU for historical reasons). That's because you want to know whether the Alt key was down when the user clicked the mouse, not whether the key is down this very instant. Whether the user released the Alt key between the time they clicked and the time you processed the message is irrelevant. You care that the Alt key was down at the time of the click.

    Note that if you are implementing a context menu handler, then you shouldn't be using either GetKeyState or GetAsyncKeyState, because the context menu can be invoked programmatically without any user action. For IContextMenu::QueryContextMenu, you should test for the CMF_EXTENDEDVERBS flag to detect whether you should display extended commands rather than querying the keyboard directly. Similarly, for IContextMenu::InvokeCommand, you should be testing the CMIC_MASK_CONTROL_DOWN and CMIC_MASK_SHIFT_DOWN flags if you want to alter your behavior based on the shift states.

    Given this primer on the difference between GetKeyState and GetAsyncKeyState, you can now explain the behavior this user is seeing.

    [Updated: 1 Dec 2004, minor typo.]

  • The Old New Thing

    Why doesn't the RunAs program accept a password on the command line?

    • 57 Comments

    The RunAs program demands that you type the password manually. Why doesn't it accept a password on the command line?

    This was a conscious decision. If it were possible to pass the password on the command line, people would start embedding passwords into batch files and logon scripts, which is laughably insecure.

    In other words, the feature is missing to remove the temptation to use the feature insecurely.

    If this offends you and you want to be insecure and pass the password on the command line anyway (for everyone to see in the command window title bar), you can write your own program that calls the CreateProcessWithLogonW function.

    (I'm told that there is a tool available for download which domain administrators might find useful, though it solves a slightly different problem.)

  • The Old New Thing

    Simple things you can do with the ShellExecuteEx function

    • 29 Comments

    Here's a tiny little program:

    #include <windows.h>
    #include <shellapi.h>
    
    int __cdecl main(int argc, char **argv)
    {
      if (argc == 3) {
        SHELLEXECUTEINFO sei = { sizeof(sei) };
        sei.fMask = SEE_MASK_FLAG_DDEWAIT;
        sei.nShow = SW_SHOWNORMAL; // added 27 Nov
        sei.lpVerb = argv[1];
        sei.lpFile = argv[2];
        ShellExecuteEx(&sei);
      }
      return 0;
    }
    

    This is a little program that takes two parameters, the first being the verb and the second the file upon which to execute the verb. Notice that since we exit immediately, we need to set the SEE_MASK_FLAG_DDEWAIT flag: Normally, the ShellExecuteEx function assumes that there will be a message pump running after it returns. This allows it to return quickly and continue any necessary DDE conversations as the responses arrive from the DDE server. But if the thread is exiting or if the thread is not a GUI thread (both of which are true here), you want to suppress this behavior because there is no message pump around to complete the DDE conversation. Setting the SEE_MASK_FLAG_DDEWAIT flag indicates that the ShellExecuteEx function should finish its DDE conversation before it returns.

    Anyway, I wrote this little program to illustrate two of the canonical verbs that you can use. It seems the people don't realize that ShellExecuteEx can be used to perform these actions, since it gets asked a lot...

    • shex find %windir%
      Opens the search window with a specified folder as the default "Search in" location.
    • shex openas C:\AUTOEXEC.BAT
      Displays the "Open with" dialog for a file.
  • The Old New Thing

    A sample of desktop icon text effects

    • 66 Comments

    It seems everybody and his brother has an obvious solution to the desktop background problem. Of course, none of these people actually tested their solution to see if it actually was usable. Because geniuses don't need to test their grand pronouncements. That's why they're called geniuses.

    Let's see how well these geniuses fared. I sat down and implemented their brilliant suggestions since I am myself not a genius.

    From left to right, the effects are as follows:

    • Solid background + text. (This is what Windows uses.)
    • Black text, no effects. (As a baseline.)
    • Xor.
    • Simple drop shadow, drawing black at (+1,+1), black at (0,0) then white at (0,0).
    • One-pixel wide outline.
    • Two-pixel wide outline.
    • 50% alpha.

    To my untrained eye, the only readable ones are the first one and the "two-pixel wide outline" (which nobody suggested but which I just made up). The enormously popular Xor is completely useless.

    Of course, all but the first three are expensive operations, requiring multiple drawing passes, so they are unsuitable for the "high performance" drawing scenario that I described in the original article.

    Therefore, the only drawing method that looks good and is also fast is the first one. And it so happens that's what Windows uses when it needs to be fast.

  • The Old New Thing

    Why can't you drop directly onto a taskbar button?

    • 73 Comments

    If you drag a object and drop it onto a taskbar button, you get an error message that says,

    You cannot drop an item onto a button on the taskbar.

    However, if you drag the item over a button without releasing the mouse button, the window will open after a moment, allowing you to drop the item inside the window.

    Why doesn't the taskbar let you drop directly onto a taskbar button?

    Ideally, if the taskbar receives a IDropTarget::Drop, it could do something like this:

    // imaginary code
    IDropTarget *pdt;
    if (SUCCEEDED(GetDropTargetFromWindow(hwndButton, &pdt))) {
      pdt->Drop(...);
      pdt->Release();
    }
    

    (Warning: I said "something like" this. Forwarding a drop is actually more complicated than this.)

    The reason why the taskbar doesn't do this is that there is no such function GetDropTargetFromWindow function. The taskbar can't forward the drop operation even if it wanted to.

    Why is there no GetDropTargetFromWindow function? I have no idea. You'll have to ask the OLE folks. If I had to guess (and I know I have to because you folks will just keep badgering me until I come up with a guess), it's because that would create the problem of how to prevent somebody from screwing with a program by grabbing its drop target and never releasing it.

    Now of course people will criticize my explanation, so I'm going to say it again: I don't know the answer. I'm just guessing. My guess is probably wrong.

  • The Old New Thing

    Why do folders like "My Pictures" come back after I delete them?

    • 47 Comments

    Some people are offended by the special folders like "My Pictures" and "My Music" and delete them, only to find them being re-created. What's going on?

    Windows itself is okay with you deleting those folders. Some corporations, for example, remove those folders from their employees' machines because they don't want the employees looking at pictures and listening to music while on the job. (Go figure.) And if the folder is deleted, Windows doesn't try to bring it back.

    However, any program can ask for the folder to be re-created. For example, if a program passes the CSIDL_FLAG_CREATE to the SHGetFolderPath function, then Windows will create the specified folder if it doesn't exist. Similarly if it passes pass fCreate = TRUE to the SHGetSpecialFolderPath function.

    If it really troubles you, you can set a creation audit on the My Pictures folder and see which program is re-creating it.

  • The Old New Thing

    When people ask for security holes as features: World-writable files

    • 39 Comments

    If I had a nickel each time somebody asked for a feature that was a security hole...

    I'd have a lot of nickels.

    For example, "I want a file that all users can write to. My program will use it as a common database of goodies."

    This is a security hole. For a start, there's an obvious denial of service attack by having a user open the file in exclusive mode and never letting go. There's also a data tampering attack, where the user opens the file and write zeros all over it or merely alter the data in subtle ways. Your music index suddenly lost all its Britney Spears songs. (Then again, maybe that's a good thing. Sneakier would be to edit the index so that when somebody tries to play a Britney Spears song, they get Madonna instead.) [Minor typo fixed. 10am]

    A colleague from the security team pointed out another problem with this design: Disk quotas. Whoever created the file is charged for the disk space consumed by that file, even if most of the entries in the file belong to someone else. If you create the file in your Setup program, then it will most likely be owned by an administrator. Administrators are exempt from quotas, which means that everybody can party their data into the file for free! (Use alternate data streams so you can store your data there without affecting normal users of the file.) And if the file is on the system partition (which it probably is), then users can try to fill up all the available disk space and crash the system.

    If you have a shared resource that you want to let people mess with, one way to do this is with a service. Users do not access the resource directly but rather go through the service. The service decides what the user is allowed to do with the resource. Maybe some users are permitted only to increment the "number of times played" counter, while others are allowed to edit the song titles. If a user is hogging the resource, the server might refuse connections for a while from that user.

    A file doesn't give you this degree of control over what people can do with it. If you grant write permission to a user, then that user can write to any part of the file. The user can open the file in exclusive mode and prevent anybody else from accessing it. The user can put fake data in the file in an attempt to confuse the other users on the machine.

    In other words, the user can make a change to the system that impacts how other users can use the system. This sort of "impact other users" behavior is something that is reserved for administrators. An unprivileged user should be allowed only to mess up his own life; he shouldn't be allowed to mess up other users' lives.

    Armed with this information, perhaps now you can answer this question posted to comp.os.ms-windows.programmer a few months ago.

  • The Old New Thing

    The various ways of sending a message

    • 51 Comments

    There are several variations on the SendMessage function, but some are special cases of others.

    The simplest version is SendMessage itself, which sends a message and waits indefinitely for the response.

    The next level up is SendMessageTimeout which sends a message and waits for the response or until a certain amount of time has elapsed. SendMessage is just SendMessageTimeout with an INFINITE timeout.

    Another version of SendMessage is SendNotifyMessage, which is like SendMessage except that it doesn't wait for the response. It returns immediately and ignores the result produced by the receiving window.

    The last SendMessage-style functions is SendMessageCallback. This sends a message and then returns immediately. When the recipient finally returns a response, the callback is called.

    SendNotifyMessage is SendMessageCallback with a callback that does nothing.

    That's how the four message-sending functions fit together.

    Bonus remark: If you use any of the above send-type functions to send a message to a window that belongs to the sending thread, the call is made synchronously.

  • The Old New Thing

    Am I sorry or not?

    • 14 Comments

    One of the consequences of the New Internet World Order is that it is very easy to set up a web site like www.sorryeverybody.com and equally easy to set up a response like www.notsorryeverybody.com. This state of affairs clearly calls out for some sort of competition between the two. At dinner last night, someone suggested that there should be a site like www.amisorryornot.com? I guess it would have been funnier if the "not sorry" site had pictures of people not being sorry. Then "sorry or not" could have picked a picture and had visitors vote whether the person looked sorry or not...

    (I have to admit in my consummate geekdom that I think that the funniest "X or not" site is www.amibiosornot.com.)

  • The Old New Thing

    If a program and a folder have the same name, the shell prefers the program

    • 26 Comments

    If you have both a folder named, say, C:\Folder and a program named C:\Folder.exe and you type C:\Folder into the Start.Run dialog, you get the program and not the folder.

    Why is that?

    Because it is common to have

     D:\Setup.exe D:\Setup\... 

    where there is a setup program in the root, as well as a setup folder containing files needed by the setup program.

    Before Windows 95, you couldn't open a folder by typing its name. (If you wanted to view it in File Manager, you had to run File Manager explicitly.) As a result, programs written for earlier versions of Windows would have instructions like

    • Insert the floppy disk labelled "Setup". (CDs were for the rich kids.)
    • From Program Manager, click File, then Run.
    • In the dialog box, type "A:\SETUP" and press Enter.

    Since there was no such thing as "opening a folder", the only option was to run the program A:\SETUP.EXE.

    Windows 95 was required to prefer the program over the folder in order that those instructions would remain valid (substituting the Start button for the File menu).

    And each version of Windows that prefers the program over the folder creates an environment wherein people who write setup programs rely on that preference, thereby securing this behavior for the next version of Windows.

    But what if you really want to open the folder?

    Append a backslash to force the path to be interpreted as a folder (A:\SETUP\).

Page 1 of 3 (27 items) 123