• The Old New Thing

    The three things you need to know about tsunamis

    • 9 Comments

    One of my friends is involved with Science on Tap, a free, informal monthly get-together in the Seattle area covering science topics for the general public. (Recent coverage in the Seattle-PI.) The topic for July 30th is "The three things you need to know about tsunamis", and a title like that pretty much sells itself.

  • The Old New Thing

    If you read any book about traditional weddings in Russian history, there must be a fight

    • 9 Comments

    You can buy a fake vacation for $500 or shell out $300 to $400 for a fake brawl at your wedding.

    "If you read any book about traditional weddings in Russian history, there must be a fight," said Alexander Yermilov, 22, who recently made a living at it.

    If you're looking for counterfeits, fakes, and forgeries, Moscow's your place. Assuming you can spot them.

    Even Putin's doctoral dissertation, researchers from the Brookings Institution revealed this year, contained major sections lifted from a text published by academics from the University of Pittsburgh.

    The revelations barely were repeated in the Moscow press, not because they were scandalous, but because they weren't—government officials routinely rely on fake dissertations patched together by underlings.

  • The Old New Thing

    Creative armed robbery defense: Political asylum

    • 9 Comments

    Step 1: Rob bank.

    Step 2: Flee the country.

    Step 3: Claim political asylum because the robbery was a form of political protest.

    It's creative, I have to grant you that. The theory is that Canadian law prohibits extradition for political crimes. Though it's a strange defense to say "If I did it, it was politically motivated." Isn't the whole point of a political protest to openly admit to the crime and invite the authorities to arrest you? If you deny doing it, then it isn't much of a political statement, now, is it?

    I mean, you don't hear on the news, "A bomb exploded in ABC today. The radical group DEF said that if they were responsible, it was in retaliation for GHI."

    (For more background, you can read a "the story so far" story from the Seattle Times.) In March, the others accused of being involved in the heist pled guilty to armed robbery, which definitely weakens the "We did it as a form of political protest" argument.

    And fleeing from house arrest while awaiting an extradition hearing certainly doesn't help either.

    Neither does running a stock scam.

  • The Old New Thing

    What do bitwise operations mean for colors?

    • 9 Comments

    Someday, you're going to pass a raster operation to the BitBlt function that entails bit manipulation. Something like SRCAND perhaps, or possibly the dreaded SRCINVERT. These bitwise operations make perfect sense for monochrome bitmaps, since those are one bit per pixel anyway. But what does it mean for color bitmaps? What do you get when you "and" together forest green (#228B22) and hot pink (#FF69B4)?

    The bitwise operations are performed in the pixel space of the destination. If the destination is a non-palettized bitmap format (higher than 8bpp), then the pixel values are red, blue and green components packed together (in various ways depending on the format). Those values are "and"ed together as integers to produce the result. For example, in a 565-format bitmap, the color forest green is represented as the value 0x2464 (0y00100`100011`00100) and hot pink is 0xFB56 (0y11111`011010`10110). The bitwise "and" of these two values is 0x2044, which is a very dark purple.

    With palettized bitmaps, the results are much less predictable since the values in the bitmap are not colors but color indices. For example, if a pixel has the value 6, that means that the color of the pixel is determined by the entry in slot 6 of the bitmap's color table, and that color could be anything. There is no rule that even requires that color 0 be black and that the highest available color be white, though most bitmaps adhere to this by convention.

    On an 8bpp bitmap, then, the question of what you get when you "and" together forest green and hot pink is underdetermined. If the color table for example happened to put forest green in slot 6 and hot pink in slot 18, the result of the "and" operation would be 6 & 18 = 2, and the result pixel would therefore be whatever color was in slot 2 of the bitmap's color table.

    What does this mean for you, adventuresome blitter?

    If you're going to use raster operations that involve bitwise operations, one of the pixels involved in the operation should be black or white (zero or all-bits-set) in order to obtain predictable results. You can then use identities like "x and black = black" and "x xor black = x" to predict the result, assuming the bitmap follows the convention for black and white noted above. But if you're going to be xor'ing with forest green, then the results could be anything.

  • The Old New Thing

    How do I prevent multi-line edit controls from eating the Enter key?

    • 9 Comments

    You might decide to put a multi-line edit control in a dialog box, not because you want the user to input multi-line data, but because it's a convenient way to display multi-line text. When you do that, you may notice that the Enter key does not invoke the default dialog button, as you might normally expect. That's because the multi-line edit control tells the dialog manager that it wants the Enter key. So how do you tell the multi-line edit control to stop doing that and let the Enter key do its normal thing?

    You already know the answer to this. As we saw quite some time ago, a control responds to the WM_GETDLGCODE message to influence the behavior of the dialog manager. In this case, the edit control is returning DLGC_WANTMESSAGE in response to the keyboard Enter key. What you want to do is prevent this from happening. You want to change the value that the edit control returns to the WM_GETDLGCODE.

    Since there is no existing window style to specify this behavior, you're left with subclassing the control and removing the DLGC_WANTMESSAGE code if the message is the Enter key.

  • The Old New Thing

    Cool web site: Bill Monk

    • 9 Comments

    One of my friends introduced me to Bill Monk, which is like PayPal but without the money. You and your friends sign up, and then you can let the site keep track of who owe whom how much.

    Of course, whether this is useful to you depends on how you and your friends actually deal with money and small debts. With some of my friends, we use the "It'll all even out in the end" strategy. We'll take turns paying for dinner and events based on the "I think it's my turn" honor system.

    With another group of friends, the bills are neatly tabulated and reckonings sent out by email for settlement. They use this system since they've known each other since college (I joined later), back when money was in short supply, and in order to accommodate group members of varying financial means. For this group, Bill Monk works great (and replaces a similar system some of us had set up to do exactly this).

  • The Old New Thing

    How to fill in that number grouping member of NUMBERFMT

    • 9 Comments

    If you look at the NUMBERFMT structure, the way groups are expressed by the Grouping member do not match the value returned by LOCALE_SGROUPING:

    LOCALE_
    SGROUPING
    Grouping Sample Culture
    3;0 3 1,234,567 United States
    3;2;0 32 12,34,567 India
    3 30 1234,567 (none I know of)

    LOCALE_SGROUPING expresses grouping as a series of semicolon-separated numbers, each expressing the number of digits in each group (least-significant group first). A trailing zero indicates that the last grouping should be repeated indefinitely. For example, "3;2;0" means "Group the three least significant digits, then in twos until you run out of digits." If there is no trailing ";0", then there are no commas past that point. For example, "3" means "Group the three least significant digits, then stop."

    The Grouping member expresses the grouping rules differently. Each significant digit represents a group, with the most significant digit representing the least-significant group, with the units digit repeated indefinitely. For example, "32" means "make a group of three digits, then group by twos thereafter." To suppress the repetition, multiply by ten.

    In other words, the two systems are basically the same, with the Grouping consisting of the LOCALE_SGROUPING string with the semicolons removed. Except that the meaning of the trailing zero is reversed, so if LOCALE_SGROUPING has a trailing zero, you have to remove it to get the Grouping, and if it lacks a trailing zero, then you have to add one to the Grouping.

    It's kind of strange that the two systems differ, considering that they both came from the same NLS team! It's probably a case of parallel evolution, wherein the locale-string folks and the number-formatting folks came up with their respective systems independently.

    Writing code to implement this conversion from LOCALE_SGROUPING to Grouping shouldn't be hard once you understand the algorithm, so I'll leave that as an exercise.

    Fortunately, in real life you rarely have need to perform this conversion, for you can just pass the desired locale as the first parameter to the GetNumberFormat (or even better, LOCALE_USER_DEFAULT), pass a NULL pointer as the lpNumberFormat, and let NLS do all the work.

  • The Old New Thing

    Index to the series on DLL imports and exports

    • 9 Comments

  • The Old New Thing

    How a less naive compiler calls an imported function

    • 9 Comments

    If a function is declared with the dllimport declaration specifier, this instructs the Visual Studio C/C++ compiler that the function in question is an imported function rather than a normal function with external linkage. With this additional information, the compiler generates slightly different code when it needs to reference an imported function, since the compiler is aware of the special way imported functions are implemented.

    First, there is no need for the stub function any more, because the compiler can generate the special call [__imp__FunctionName] instruction inline. Furthermore, the compiler knows that the address of an imported function never changes, and consequently it can optimize away multiple loads of the function pointer:

        mov   ebx, [__imp__FunctionName]
        push  1
        call  ebx ; FunctionName(1)
        push  2
        call  ebx ; FunctionName(2)
    

    (Note to crazy people: This optimization means that you can run into problems if you patch a module's import table once it has started running, because the function pointer may have been optimized into a register before you patched the import. Consider, in the above example. that you patched the __imp__FunctionName table entry after the mov ebx, [__imp__FunctionName] instruction: Your replacement import table entry won't be called since the old function address was cached in the ebx register.)

    Similarly, if your program tries to take the address of an imported function that has been declared with the dllimport declaration specifier, the compiler recognizes this and converts it to a load from the imported function address table.

    As a result of this extra knowledge imparted to the compiler, the stub function is no longer needed; the compiler knows to go straight to the imported function address table.

    Note that there are still occasional circumstances wherein you can induce the stub function to be created. We'll take a look at them (and related dangers) next time.

  • The Old New Thing

    How were window hooks implemented in 16-bit Windows?

    • 9 Comments

    The mechanism for keeping track of window hooks was very different in 16-bit Windows. The functions involved were SetWindowsHook, UnhookWindowsHook and DefHookProc. The first two functions still exist today, but the third one has been replaced with a macro:

    // 16-bit prototype
    DWORD WINAPI DefHookProc(int nCode, WPARAM wParam,
                             LPARAM lParam, HHOOK FAR *phk);
    
    // 32-bit macro
    #define DefHookProc(nCode, wParam, lParam, phhk)\
            CallNextHookEx(*phhk, nCode, wParam, lParam)
    

    Disclaimer: All code below is "reconstructed from memory". The spirit of the code is intact, but the precise details may be off.

    To install a windows hook in 16-bit Windows, you started by calling SetWindowsHook:

    HHOOK g_hhkPrev;
    
    g_hhkPrev = SetWindowsHook(WH_WHATEVER, MyHookProc);
    

    The return value from SetWindowsHook must be saved in a global variable, which we gave the somewhat provocative name g_hhkPrev. The hook procedure itself went something like this:

    // In Win16, hook procedures returned a DWORD, not an LRESULT.
    DWORD CALLBACK MyHookProc(int nCode, WPARAM wParam, LPARAM lParam)
    {
      if (nCode >= 0) { ... }
      return DefHookProc(nCode, wParam, lParam, &g_hhkPrev);
    }
    

    And then when you were finished, you removed the hook by calling UnhookWindowsHook:

    UnhookWindowsHook(WH_WHATEVER, MyhookProc);
    g_hhkPrev = NULL;
    

    Internally, the chain of hook functions was managed as a linked list, but instead of using some internal data structure to keep track of the hooks, the linked list was managed inside the HHOOK variables themselves.

    The internal implementation of SetWindowsHook was simply this:

    // This array is initialized with a bunch
    // of "do nothing" hook procedures.
    HOOKPROC g_rgHook[NUMHOOKS];
    
    HHOOK WINAPI SetWindowsHook(int nType, HOOKPROC pfnHookProc)
    {
     HHOOK hhkPrev = (HHOOK)g_rgHook[nType];
     g_rgHook[nType] = pfnHookProc;
     return hhkPrev;
    }
    

    Installing a hook merely set your hook procedure as the head of the hook chain, and it returned the previous head. Invoking a hook was a simple matter of calling the hook at the head of the chain:

    DWORD CallHook(int nType, int nCode, WPARAM wParam, LPARAM lParam)
    {
     return g_rgHook[nType](nCode, wParam, lParam);
    }
    

    Each hook procedure did its work and then sent the call down the hook chain by calling DefHookProc, passing the HHOOK by address.

    DWORD WINAPI DefHookProc(int nCode, WPARAM wParam,
                             LPARAM lParam, HHOOK FAR *phk)
    {
     HOOKPROC pfnNext = (HOOKPROC)*phk;
     if (nCode >=0) {
      return pfnNext(nCode, wParam, lParam);
     }
     ... more to come ...
    }
    

    As you can see, it's all blindingly simple: Invoking a hook calls the first hook procedure, which then calls DefHookProc, which knows that a HHOOK is just a HOOKPROC, and it forwards the call down the chain by merely calling the next hook procedure directly.

    The real magic happens when somebody wants to unhook. Recall that the rule for hook procedures is that a negative hook code should be passed straight to DefHookProc (or in modern times, CallNextHookEx). This convention allows the hook system to use negative codes to manage its own internal bookkeeping. In this case, we're using -1 as the "unhook this hook procedure" code.

    BOOL WINAPI UnhookWindowsHook(int nType, HOOKPROC pfnHookProc)
    {
     return DefHookProc(-1, 0, (LPARAM)pfnHookProc,
                        (HHOOK FAR*)&g_rgHook[nType]);
    }
    
    And then the real magic begins:

    DWORD WINAPI DefHookProc(int nCode, WPARAM wParam,
                             LPARAM lParam, HHOOK FAR *phk)
    {
     HOOKPROC pfnNext = (HOOKPROC)*phk;
     if (nCode >=0) {
      return pfnNext(nCode, wParam, lParam);
     }
     switch (nCode) {
     case -1: // trying to unhook a node
      if (pfnNext == (HOOKPROC)lParam) { // found it
       *phk = (HHOOK)pfnNext(-2, 0, 0);
       return TRUE;
      }
      // else keep looking
      return pfnNext(nCode, wParam, lParam);
    
     case -2: // report the next hook procedure
       return (DWORD)*phk;
     }
     return 0;
    }
    

    And there you have it, the entire window hook system in two dozen lines of code. You have to give 16-bit Windows credit for being small.

    Let's walk through hook installation, dispatch, and removal to see how this all works. Suppose there is one WH_KEYBOARD hook in the system. Our variables are therefore set up like this:

    // In USER
    g_rgHook[WH_KEYBOARD] = Hook1;
    
    // In HOOK1.DLL
    HHOOK g_hhkPrev1 = DoNothingHookProc;
    
    DWORD CALLBACK Hook1(int nCode, WPARAM wParam, LPARAM lParam)
    {
     if (nCode >= 0) { ... work ... }
     return DefHookProc(nCode, wParam, lParam, &g_hhkPrev1);
    }
    

    Now suppose you want to install a new hook, Hook2.

    // In HOOK2.DLL
    HHOOK g_hhkPrev2;
    
    g_hhkPrev = SetWindowsHook(WH_KEYBOARD, Hook2);
    

    The SetWindowsHook function just puts your function in as the new "head" hook function and returns the old one.

    // In USER
    g_rgHook[WH_KEYBOARD] = Hook2;
    
    // In HOOK2.DLL
    HHOOK g_hhkPrev2 = Hook1;
    
    DWORD CALLBACK Hook2(int nCode, WPARAM wParam, LPARAM lParam)
    {
     if (nCode >= 0) { ... work ... }
     return DefHookProc(nCode, wParam, lParam, &g_hhkPrev2);
    }
    
    // In HOOK1.DLL
    HHOOK g_hhkPrev1 = DoNothingHookProc;
    
    DWORD CALLBACK Hook1(int nCode, WPARAM wParam, LPARAM lParam)
    {
     if (nCode >= 0) { ... work ... }
     return DefHookProc(nCode, wParam, lParam, &g_hhkPrev1);
    }
    

    Now suppose the window manager decides it's time to fire the WH_KEYBOARD hook. It starts with CallHook which calls g_rgHook[WH_KEYBOARD] that takes us to Hook2. That hook function does its work, then calls DefHookProc(..., &g_hhkPrev2), which dispatches the hook to g_hhkPrev2 == Hook1. Similarly, the hook travels through Hook1, then DefHookProc(..., &g_hhkPrev1), where it finally reaches the DoNothingHookProc which does nothing and ends the hook chain.

    Now suppose that HOOK1.DLL decides to uninstall its hook. It therefore calls UnhookWindowsHook(WH_KEYBOARD, Hook1). This starts off the hook chain with the internal hook code -1 and &g_rgHook[WH_KEYBOARD] as the first hook pointer. This activates the case -1 in DefHookProc code path, which dereferences its phk parameter and obtains g_rgHook[WH_KEYBOARD] == Hook2. Since this is not equal to Hook1, the call forwards down the chain to Hook2.

    Like a good hook function, Hook2 reacts to the negative hook code by handing the call directly to DefHookProc(-1, ..., &g_hhkPrev2). This time, *phk == g_hhkPrev2 == Hook1, so the test succeeds and we dispatch the hook down the chain with a new internal code of -2, which means, "Tell me what the next hook procedure is".

    This dispatch calls Hook1 which (since the notification code is negative) immediately passes the call to DefHookProc(-2, ..., &g_hhkPrev1). This now triggers the case -2 code path, which just returns *phk == g_hhkPrev1 == DoNothingHookProc. This value is returned to the DefHookProc(-1, ...) which stores the result into *phk == g_hhkPrev2; the result is that you have g_hhkPrev2 = DoNothingHookProc. Finally, DefHookProc returns TRUE to indicate that the hook was successfully uninstalled. This value is then returned out from all the nested function calls to the original caller of UnhookWindowsHook.

    Observe that at the end of this unhook exercise, we get the desired result:

    // In USER
    g_rgHook[WH_KEYBOARD] = Hook2; // unchanged
    
    // In HOOK2.DLL
    g_hhkPrev2 = DoNothingHookProc; // updated!
    
    DWORD CALLBACK Hook2(int nCode, WPARAM wParam, LPARAM lParam)
    {
     if (nCode >= 0) { ... work ... }
     return DefHookProc(nCode, wParam, lParam, &g_hhkPrev2);
    }
    

    And Hook1 is out of the hook chain, as we desired.

    This really isn't all that complicated. All we did was delete a node from a linked list. It's just that this particular linked list cannot be traversed by just dereferencing pointers. Instead, we have to issue a function call and ask the recursive function to perform the work on the "next" node for us. That's what the negative nCode values are for.

    Every time I work through this exercise, I am impressed by how compactly 16-bit Windows was written. In just two dozen lines of code, we managed a linked list of function calls, including a dispatching system as well as arbitrary deletion from the middle of the linked list, and all without any memory allocation.

    (And because I know people are going to try to change the topic: Remember, I'm talking about 16-bit Windows, not 32-bit window hooks.)

    Next time, we'll look at one way people abused this simple system.

Page 374 of 450 (4,495 items) «372373374375376»