April, 2007

  • The Old New Thing

    What is the default version of a header file?

    • 34 Comments

    The general rule with Windows header files is that if you don't specify which version of the header file you want, you get the latest version. For example, if you have the Windows XP Platform SDK header files and you #include <windows.h>, you're going to get the Windows XP function prototypes, the Windows XP structures, the the Windows XP flags, all that stuff. And unless you're careful, the program you get as a result will most likely run only on Windows XP.

    If you call a function that is new for Windows XP, then your program won't run on earlier versions of Windows because the import can't be resolved.†

    If you use a structure that changed for Windows XP, then your program won't run on earlier versions of Windows because the structure size will be wrong.

    Even if the structure size didn't change, using a flag that was introduced in Windows XP will create difficulties for your program when run on earlier versions of Windows because those earlier versions don't support the flag you're passing. Depending on how the function in question was written, it may ignore the "flag from the future" or it may reject it as invalid.

    If you want your program to run on older versions of Windows, you have a few options. First, you can explicitly "downgrade" your header file by defining an appropriate symbol or symbols before including the windows.h header file.

    #define WINVER         0x0400
    #define _WIN32_WINNT   0x0400
    #define _WIN32_WINDOWS 0x0400
    #define _WIN32_IE      0x0400
    
    #include <windows.h>
    #include <commctrl.h>
    #include <shlobj.h>
    ...
    

    Oh yuck, now we have the messy world of "So what's the difference between _WIN32_WINNT, _WIN32_WINDOWS, _WIN32_IE, and WINVER?" We'll pick up this topic next time, but you're not going to like the answer.

    Nitpicker's corner

    †That statement is from the operating system's‡ point of view. You can of course use techniques like Visual Studio linker's delay-load feature to avoid creating an import dependency, but that's outside the operating system.‡

    ‡s/operating system/Windows operating system/

  • The Old New Thing

    Changes to power management in Windows Vista

    • 70 Comments

    As I noted some time ago, it's hard to get programmers excited about power management. What's worse, programs that do take the effort to care about power management often do it rudely, hijacking your computer and preventing you from going into standby or hibernation, instead preferring to drain your battery until the computer just dies from lack of power.

    The Power Management folks decided that they've had enough with these selfish programs and redesigned the way power management works. In addition to exposing finer control over various aspects of power management to the user, they also decided to "take the ball and go home" when it comes to programs rejecting suspend or hibernation requests. When the user asks for the computer to go into a low power state, programs will get notified of the state change but are not allowed to veto it. Programs get two seconds to clean up, and then that's it. The laptop is going into standby, ready or not.

    If you ordered a copy of the PDC DVDs, you can go back and watch session FUN319 to learn more. (Here are some follow-up remarks to that session.) I'm not the expert in this area; I'm just repeating what I've heard. If you have questions about the future of power management, you probably should ask the power management folks over on the Windows Mobile PC Team Blog.

  • The Old New Thing

    Why do operating system files still adhere to the old 8.3 naming convention?

    • 44 Comments

    Commenter Brian Reiter asks a duplicate of a question that was already submitted to the Suggestion Box: Darren asks why operating system† files still (for the most part) adhere to the old 8.3 naming convention.

    There are a few reasons I can think of. I'm not saying that these are the reasons; I'm just brainstorming.

    First, of course, the name of a DLL cannot change once it has been chosen, because that would break programs which linked to that DLL by its old name. Windows 95 did not require the system volume and user profile volume to support long file names, although that was certainly the case by default. Companies which used roaming profiles or redirected folders may have had a heavy investment in servers which did not support long file names. Therefore, all system files on Windows 95 had to conform to the 8.3 naming convention.

    I believe that Windows NT permitted the system volume to be a short-file-names-only FAT partition as late as Windows 2000. Therefore, any DLL that existed in the Windows 2000 era had to conform to the 8.3 naming convention.

    Starting in Windows XP, long file names became mandatory, and a few system files such as shellstyle.dll waded tentatively into the long file name world. (The .NET Framework folks jumped in with both feet with their managed DLLs, but notice that their unmanaged DLLs like mscoree.dll still conform to 8.3.) But the waters in this world can be treacherous for operating system components.

    First of all, you have to worry about the automatically-generated short name. Suppose the operating system setup program is copying the shellstyle.dll file, but there is already a file called shellstuff.dll. The short name for shellstuff.dll will probably be SHELLS~1.DLL, and therefore the short name for shellstyle.dll will likely be SHELLS~2.DLL. Now, this may not be a big deal, except that some programs like to hard-code a file's short name. (There are a lot of programs that assume that the Program Files directory is C:\PROGRA~1, for example.)

    Furthermore, you can create confusion if the same DLL is loaded by both its short and long names, since the loader treats them as distinct:

    #include <stdio.h>
    #include <windows.h>
    
    int __cdecl main(int argc, char **argv)
    {
     printf("%p\n", LoadLibrary("SHELLS~1.DLL"));
     printf("%p\n", LoadLibrary("SHELLSTYLE.DLL"));
     return 0;
    }
    

    If you run this program, you will get something like this:

    6F2C0000
    00340000
    

    Even though the two paths refer to the same DLL, the loader treats them as different, and you end up with two copies of the same DLL loaded into memory. Now things get confusing, since you now have two sets of global variables, and if two components both use SHELLSTYLE.DLL but one used the short name and the other the long name, things get exciting when those two components try to talk about what they think is the same thing.

    It's like that time when I was a child and our family took a trip to Disneyland. Our parents put my brother and me on the gondola ride, and upon arrival at the other end, we were to go to the Autopia ride which was right next door. The plan was that our parents would meet us at the exit to Autopia. When my brother and I exited Autopia, we expected our parents to be waiting there for us, but they were nowhere to be seen. Sticking to the plan, we waited patiently for our parents to arrive. We sat there for what seemed like two hours (but which was probably much less), until eventually we decided that my brother would stay put and I would go looking around, at which point it didn't take long for me to find my father, who was walking around looking for us.

    What went wrong? Well, the problem was that the map of Disneyland showed Autopia, but what the map didn't say was that there were two Autopia rides (and therefore two Autopia exits) right next to each other. My brother and I were waiting by one exit, and our parents were waiting by the other. Each of us thought the other party was simply late.

    Similarly, if a DLL goes by multiple names, you can end up with two copies of it loaded into the process, with different components talking about different copies, unaware that they are talking about different things.

    And one final reason I can think of for sticking with 8.3 file names for operating system DLLs is simply, "Well, that's the way we've always done it. All the problems with 8.3 names are well-understood and under control. If we switched to long file names, we'd end up discovering a whole new set of problems. Why mess with something that works if it isn't broken?"

    Better the devil you know.

    Exercise: Why is it okay for the .NET Framework to use long file names for their managed DLLs?

    Nitpicker's Corner

    †s/operating system/Windows operating system/. Apparently nothing is obvious from context any more.

  • The Old New Thing

    What's the row of numbers on the copyright page of books?

    • 21 Comments

    On the copyright page of a book (typically the back of the title page), you'll find a row of numbers. Something like this:

    Printed in the United States of America
    10   9   8   7   6   5   4   3   2   1

    As Dave Taylor explains, the smallest number tells you which printing of the book you have. For example, if you see "10 9 8 7 6 5 4" then you have a fourth printing. Dave doesn't explain why printers use this convention, however.

    I forget where I learned this; I think I read it in one of Don Knuth's books. It has to do with how books are historically made. Each page of a book is converted to a metal plate which is used to make impressions. If another printing run is necessary, you load the plates back onto the printing machine and off you go. But how do you indicate that this is a second printing? It would be expensive to burn a brand new plate just to change the word "first" to "second" on the copyright page. Instead, you pre-load all the printing numbers onto your master, and each time you start a new printing run, you scratch off the lowest number.

    Even though a lot of book printing nowadays is done with computers rather than metal plates, the old method of indicating a printing is retained out of tradition.

  • The Old New Thing

    The Notepad file encoding problem, redux

    • 65 Comments

    About every ten months, somebody new discovers the Notepad file encoding problem. Let's see what else there is to say about it.

    First of all, can we change Notepad's detection algorithm? The problem is that there are a lot of different text files out there. Let's look just at the ones that Notepad supports.

    • 8-bit ANSI (of which 7-bit ASCII is a subset). These have no BOM; they just dive right in with bytes of text. They are also probably the most common type of text file.
    • UTF-8. These usually begin with a BOM but not always.
    • Unicode big-endian (UTF-16BE). These usually begin with a BOM but not always.
    • Unicode little-endian (UTF-16LE). These usually begin with a BOM but not always.

    If a BOM is found, then life is easy, since the BOM tells you what encoding the file uses. The problem is when there is no BOM. Now you have to guess, and when you guess, you can guess wrong. For example, consider this file:

    D0 AE
    

    Depending on which encoding you assume, you get very different results.

    • If you assume 8-bit ANSI (with code page 1252), then the file consists of the two characters U+00D0 U+00AE, or "Ю". Sure this looks strange, but maybe it's part of the word VATNIЮ which might be the name of an Icelandic hotel.
    • If you assume UTF-8, then the file consists of the single Cyrillic character U+042E, or "Ю".
    • If you assume Unicode big-endian, then the file consists of the Korean Hangul syllable U+D0AE, or "킮".
    • If you assume Unicode little-endian, then the file consists of the Korean Hangul syllable U+AED0, or "껐".

    Okay, so this file can be interpreted in four different ways. Are you going to use the "try to guess" algorithm from IsTextUnicode? (Michael Kaplan has some thoughts on this subject.) If so, then you are right where Notepad is today. Notice that all four interpretations are linguistically plausible.

    Some people might say that the rule should be "All files without a BOM are 8-bit ANSI." In that case, you're going to misinterpret all the files that use UTF-8 or UTF-16 and don't have a BOM. Note that the Unicode standard even advises against using a BOM for UTF-8, so you're already throwing out everybody who follows the recommendation.

    Okay, given that the Unicode folks recommend against using a BOM for UTF-8, maybe your rule is "All files without a BOM are UTF-8." Well, that messes up all 8-bit ANSI files that use characters above 127.

    Maybe you're willing to accept that ambiguity, and use the rule, "If the file looks like valid UTF-8, then use UTF-8; otherwise use 8-bit ANSI, but under no circumstances should you treat the file as UTF-16LE or UTF-16BE." In other words, "never auto-detect UTF-16". First, you still have ambiguous cases, like the file above, which could be either 8-bit ANSI or UTF-8. And second, you are going to be flat-out wrong when you run into a Unicode file that lacks a BOM, since you're going to misinterpret it as either UTF-8 or (more likely) 8-bit ANSI. You might decide that programs that generate UTF-16 files without a BOM are broken, but that doesn't mean that they don't exist. For example,

    cmd /u /c dir >results.txt
    

    This generates a UTF-16LE file without a BOM. If you poke around your Windows directory, you'll probably find other Unicode files without a BOM. (For example, I found COM+.log.) These files still "worked" under the old IsTextUnicode algorithm, but now they are unreadable. Maybe you consider that an acceptable loss.

    The point is that no matter how you decide to resolve the ambiguity, somebody will win and somebody else will lose. And then people can start experimenting with the "losers" to find one that makes your algorithm look stupid for choosing "incorrectly".

  • The Old New Thing

    What's the difference between WINVER, _WIN32_WINNT, _WIN32_WINDOWS, and _WIN32_IE?

    • 33 Comments

    Okay, so there are all these different ways you can specify what version of the Windows header files you want.†

    #define WINVER         0x0400
    #define _WIN32_WINNT   0x0400
    #define _WIN32_WINDOWS 0x0400
    #define _WIN32_IE      0x0400
    

    Let's take them in order.

    The WINVER symbol is the earliest one. That's the symbol that 16-bit Windows used to control the versioning of its header files, and its use carried forward into the 32-bit header files, presumably from the people who did the initial conversion of the header files to 32-bit and who grew up with the WINVER symbol. This symbol is still used a lot in the header files that can trace their origins to 16-bit Windows, such as winuser.h, wingdi.h, and mmsystem.h.

    The _WIN32_WINNT symbol came next. I'm not sure where it came from, but from its name it probably was invented by the Windows NT team in order to allow them to block off sections of the header file that are available only in the Windows NT implementation of Win32. Don't forget that in the early days, there was also Win32s, a subset of Win32 that could run on 16-bit Windows 3.1. The single WINVER symbol wasn't enough to specify exactly what you wanted to be compatible with. For example, a function available only in Windows NT 3.1 would be guarded with #if _WIN32_WINNT >= 0x030A so that programs that wanted to run on Win32s could set _WIN32_WINNT to zero and keep that function off-limits.

    Similarly, both Windows 95 and Windows NT 4 identified themselves as Windows major version 4, so the WINVER symbol was insufficient to distinguish them. Functions that existed in Windows NT 4 but not in Window 95 were therefore guarded with _WIN32_WINNT.

    On the other hand, there were also functions that were first introduced in Windows 95 and did not exist in the original version of Windows NT 4. The _WIN32_WINDOWS symbol let you specify that you wanted access to stuff that was new for Windows 95 and which would also be ported to Windows NT 4 and future versions of Windows NT.

    The next symbol in this progression is _WIN32_IE, which lets you specify what version of Internet Explorer you require to be installed on the system. This was more important back in the days when Internet Explorer included updates to selected operating system components. For example, Internet Explorer 4 came not only with an updated comctl32.dll but also a new shell32.dll that gave you Active Desktop. (Wow, remember Active Desktop? That was when everybody thought that HTML was going to take over the world and people would write entire applications in HTML. People are still trying.)

    And history repeated itself: We saw it before when we tried to puzzle out why some functions return NULL while others return INVALID_HANDLE_VALUE. Each time somebody added a new feature to Windows and had to add an #ifdef guard, it was pretty much a toss-up whether they would use WINVER, _WIN32_WINDOWS, or _WIN32_WINNT. Once Internet Explorer stopped including updates to shell components, _WIN32_IE fell into the "toss-up" bucket as well.

    In an attempt to make some sense out of this disaster, the SDK and DDK teams came up with a new plan for Windows Vista header files: sdkddkver.h. There's now just one symbol you define to specify your minimum target operating system: NTDDI_VERSION. Once you set that, all the other symbols are set automatically to the appropriate values for your target operating system. (And no, I don't know what the letters NTDDI stand for, though there is one obvious candidate.) With any luck, everybody wll standardize on NTDDI_VERSION and this article will become one of those "quaint historical novelties" like all the ones about 16-bit Windows. Just "a little story about what people had to do back in the crazy days of the early 21st century. Boy am I glad we don't have to worry about that any more!"

    Notes

    I'd appreciate it if people would extend me the courtesy of not stepping on my announced topic. (I wonder if these are the same people who go to a comedy show and shout out the punch lines before the performer gets to say them.) I did say that I would pick up the topic today, after all. If you really want to steal my topic, at least be polite enough to post your essay on your own blog.

    Nitpicker's corner

    †This list is not intended to be comprehensive.

  • The Old New Thing

    The wisdom of seventh graders: Designing an elective course

    • 43 Comments

    Last month, I spent a few hours reading essays written by seventh graders (ages 12 and 13) on the following subject:

    Electives are often fun and different from our normal core classes. Imagine you have been chosen to create one new elective for our school. In a multi-paragraph essay, explain what the new elective would be like and what students would learn.

    (Students were given two hours, plus one additional hour upon request.)

    Before I present you some of the responses, I'd like to take some time to address the students on the subject of writing. I know they won't read this, but I have to tell someone.

    • Stay on prompt; in other words, make sure you address the assigned topic in its entirety. Don't get so carried away describing the class itself that you forget to explain what students would learn. Going off prompt is an automatic disqualification.
    • Stay on mode; in other words, write the type of essay requested. This example demands an expository essay, not a persuasive one. You aren't trying to convince other students to take your elective. As with going off prompt, going off mode is an automatic disqualification.
    • Do not introduce new material in your conclusion. Your conclusion is for tying your argument together; it's not a place for "oh, wait, I forgot something."
    • Take it easy with the exclamation points! It's really distracting!
    • Inside these questions there is often hidden another question, usually a Why. Here, the hidden question is "Why is it important that students learn that which this elective teaches?" Addressing the hidden question takes your essay to the next level. This tip is only for advanced writers; don't even consider addressing the hidden question until you can handle the explicit one!
    • Mind your frame of reference. Don't start with students and then switch to you. Example of error (exaggerated): "Students who complete this class can show off to your friends." I'd say that over half of the essays made mistakes like this, though none so blatant.
    • Mind your antecedents. When you use a pronoun, make sure the noun to which it refers is unambiguous. Example of error: "If teachers or anyone else hears insults, they will be thrown out of class."
    • I'm sure there are adjectives other than cool and fun. Try using them once in a while. It's cool and fun.
    • Many rules of writing can be broken, but don't break a rule until you've first mastered it. Richard Wagner can write an orchestral prelude that consists of a single chord for over four minutes, but that's because he's Richard Wagner, and he knows what he's doing.

    What electives would seventh-graders design for themselves? Here are the ones from the essays that I read (plus some that other readers shared with me, marked with asterisks), broken down roughly into categories, and illustrated with selected sentences from those essays or closely-related essays.

    • Sports and exercise
      • Skateboarding.
      • Fencing.
      • Cricket.
      • Soccer. The student explains that the problem with standard gym classes is that you don't get to spend much time focusing on any one sport. "This class will have more variety than any other class."
      • *Basketball. "Shooting is a exceedingly important part of basketball because if you didn't score you would have no points. Shooting well helps your team's chances of winning the game."
      • *Swimming. This essay had an excellent introductory paragraph that ended with "We need more electives. We need variety. We need swimming." It's a joy to read from students who have such control of writing that they can explore rhetorical devices.
      • Paintballing [sic]. "There is not another elective where the goal is to shoot another student to win." (How about photography?)
      • A single sport (chosen by the student).
      • Exercise for students who are overweight or have physical disabilities.
      • Weight training. It "strenthens strength."
      • *Skydiving.
    • Arts
      • Glass blowing.
      • Metal shop. (The school already offers woodworking.)
      • Drawing. "There is, quite literally, a fine line between a sketch of a drawing and the actual drawing."
      • Cartooning.
      • Architecture.
      • Creative writing (2×).
      • *Rock music performance. "Would you rather be shreding (on the guitar) or playing Betovon."
    • Sciences
      • Electronics.
      • Material science.
      • *Writing video games. "Each kid would pay a fee of $20 to pay some real progromers to teach the class for a year."
    • Personal development
      • Make-up and beauty.
      • Style and fashion. Specifically, shopping for clothes.
      • Self-image improvement. Specifically, by improving one's hairstyle ("Braids, twists, and buns, OH MY!"), make-up, and fashion sense. "From color choices to what fashion style best suits them, it can get very confussing."
      • Information. A combination of writing and public speaking. The student's recommendations for presentations? The second slide should contain ten bullet points. "The third slide would be a five paragraph essay about the topic."
    • Languages and cultures
      • Foreign travel. "The students might have to take quizzes." The class concludes with trips to seven countries, each lasting one week. "It would be worth it to say, 'I have been to all seven countries just in Middle school.'" The student acknowledged that this class would be expensive. "It will cost you 1000 dollars to get your seven tickets to fly to all those countries."
      • Foreign language (unspecified). (Most schools in the United States do not introduce foreign languages until high school, typically age 14.)
      • Mandarin Chinese (2×).
    • Life skills
      • Introduction to automobile driving and safety. Students are too young to drive cars, so they will train on go-karts. "Go-karting would allow you to practice those basics so much that driving a car would be a walk in the park."
      • Wilderness survival. The final exam is a practical.
    • Careers
      • How to get a job. Focusing on the mechanics, like filling out an application.
      • Choosing a career. Students research various careers to learn more about them.
      • Veterinarian. "This elective would teach students all that they need to know to become a vet such as the basics of being a veterinarian and how to treat animals." The basics are all you need to know!
      • Doctor. Students will attend class in surgical scrubs and perform dissections and autopsies. Field trips include going to a local hospital and assisting an actual doctor. (You are responsible for your own malpractice insurance.) "In conclusion, having a class about what a doctor does is what we should have at our school because it is informative yet amusing."
    • Wildcard
      • *"I sugjest reshersh and repor class."
      • *Adobe Photoshop. This essay was a one-page advertisement for Photoshop, going into the product's features in fantastic detail.
      • Fire.
      • Inventing. Students will create an invention over the course of the term.
      • Television appreciation. "Our current electives require thought and work. ... This class is a much needed easy A+. ... This class will prepare our students for the real world. You can learn more life lessons in an episode of Spong Bob than the average person can learn in his life. ... Watching mindless television for a whole period for credit will be a great elective."
      • *Being lazy. This student cut to the chase. Not like that "television appreciation" student who tried to disguise it as something remotely educational.
      • "Social hall." This class is limited to fifteen students and consists only of students you choose to take it with. One of the school buildings will be converted to "social hall," with one classroom for doing homework, another classroom converted to a movie theater, and others available just for hanging out with your friends. Food and beverages will be provided, of course. There is no examination. "I think Social hall would be an excellent elective. Students will inhance social skills, physical skills and eating ideas."
      • "Anything you want." Students are free to roam the campus for this double-length period. "It would be the greatest elective yet to be invented. There will be no teachers, no rules, no fighting."

    Other sentences, taken completely out of context for maximum amusement.

    • *"Sure fit people are in good shape but they nee exersise too."
    • "Students would prefer it for its ingenuous content."
    • "There is only so long a 7th grader can sit in a cluttered room and write." (A comment on the assignment, perhaps?)
    • *"In this class, students will learn how to vacation."
    • *"We would be able to go to the lake three times a week, Tuesdays and Thursdays."
    • *"It would most likely shock the students that when you have a job you have to do just about everything by yourself."
    • *"Art is hard and easy but not both."

    Spelling corner: See if you can guess the word before reading the answer.

    soddering hazardist conclonstion
    gragwwhts Joner of Achievement
    tords enchurens

    Best new word: "confussing"

    Note: Hover over dotted words for explanations/answers.

  • The Old New Thing

    Email tip: People didn't answer your first email for a reason

    • 60 Comments

    It is said that insanity is doing the same thing over and over again and expecting different results. Consider:

    From: X
    To: Group Y

    Question blah blah blah.

    A day or two later:

    From: X
    To: Group Y

    Resending due to no response.

    ------- Original Message -------
    From: X
    To: Group Y

    Question blah blah blah.

    You didn't get a response because your previous message was poorly-phrased, or it was sent to the wrong group, or nobody recognized the question as something they could help with, or any of a number of possible reasons. Re-sending it is not going to fix that. If your question was poorly-phrased, it's still poorly-phrased. The only difference is that now, it's been poorly-phrased twice.

    If you're compelled to re-send your question, add information to make it more likely that somebody will respond to the second one. If you merely repeat the question, you're just going to get the same response. (I.e., none.)

  • The Old New Thing

    Code is read much more often than it is written, so plan accordingly

    • 53 Comments

    Design for readability.

    Even if you don't intend anybody else to read your code, there's still a very good chance that somebody will have to stare at your code and figure out what it does: That person is probably going to be you, twelve months from now.

    When I advised against the use of BOOL function parameters, one commenter pointed out that Intellisense shows you what the parameters are. Sure, that's a great help when you're writing the code, but you write the code only once. You read it a lot.

    An anonymous commenter pointed out that hovering over the offending function in the IDE shows the function declaration. While that may be true, it's still not a great solution. First, it means that you have to read code with your hand on the mouse. Second, it means that you can't skim code because you're going to hit a CreateEvent and then have to wait a little while for the tooltip to appear and then read and parse the tooltip and match the parameters up to what you have on the screen. This throws off your rhythm.

    Imagine if you had to read code that had gone through a ROT-13 filter. Sure, the IDE might help you by decoding the text under the cursor if you hover over it, but even instant help isn't fast enough.

    And finally, another commenter pointed out that this doesn't help you if you're reading code anywhere outside your IDE. It might be in a magazine, in a printout, in a bug report, on an overhead projector, on a web page, in a Usenet message, or in an email message. Good luck getting Intellisense to help you out there.

  • The Old New Thing

    Stupid debugger tricks: Calling functions and methods

    • 14 Comments

    Back in the old days, if you wanted to call a function from inside the debugger, you had to do it by hand: Save the registers, push the parameters onto the stack (or into registers if the function uses fastcall or thiscall) push the address of the ntdll!DbgBreakPoint function, move the instruction pointer to the start of the function you want to call, then hit "g" to resume execution. The function runs then returns to the ntdll!DbgBreakPoint, where the debugger regains control and you can look at the results. Then restore the registers (including the original instruction pointer) and resume debugging. (That paragraph was just a quick recap; I'm assuming you already knew that.)

    The Windows symbolic debugger engine (the debugging engine behind ntsd, cdb and windbg) can now automate this process. Suppose you want to call this function:

    int DoSomething(int i, int j);
    

    You can ask the debugger to do all the heavy lifting:

    0:001> .call ABC!DoSomething(1,2)
    Thread is set up for call, 'g' will execute.
    WARNING: This can have serious side-effects,
    including deadlocks and corruption of the debuggee.
    0:001> r
    eax=7ffde000 ebx=00000001 ecx=00000001 edx=00000003 esi=00000004 edi=00000005
    eip=10250132 esp=00a7ffbc ebp=00a7fff4 iopl=0         nv up ei pl zr na po nc
    cs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000             efl=00000246
    ABC!DoSomething:
    10250132 55               push    ebp
    0:001> dd esp
    00a7ffbc  00a7ffc8 00000001 00000002 ccfdebcc
    

    Notice that the debugger nicely pushed the parameters onto the stack and set the eip register for you. All you have to do is hit "g" and the DoSomething function will run. Once it returns, the debugger will restore the original state.

    This technique even works with C++ methods:

    // pretend that we know that 0x00131320 is an IStream pointer
    0:001> .dvalloc 1000
    Allocated 1000 bytes starting at 00a80000
    0:001> .call ABC!CAlphaStream::Read(0x00131320, 0xa80000, 0x1000, 0)
    Thread is set up for call, 'g' will execute.
    WARNING: This can have serious side-effects,
    including deadlocks and corruption of the debuggee.
    

    Notice that when calling a nonstatic C++ method, you have to pass the "this" parameter as an explicit first parameter. The debugger knows what calling convention to use and puts the registers in the correct location. In this case, it knew that CAlphaStream::Read uses the stdcall calling convention, so the parameters have all been pushed onto the stack.

    And what's with that .dvalloc command? That's another debugger helper function that allocates some memory in the debugged process's address space. Here, we used it to allocate a buffer that we want to read into.

    But what if you want to call a method on an interface, and you don't have the source code to the implementation? For example, you want to read from a stream that was passed to you from some external component. Well, you can play a little trick. You can pretend to call a function that you do have the source code to, one that has the same function signature, and then move the eip register to the desired entry point.

    // pretend that we know that 0x00131320 is an IStream pointer
    0:000>  dp 131320 l1
    00131320  77f6b5e8 // vtable
    0:000> dps 77f6b5e8 l4
    77f6b5e8  77fbff0e SHLWAPI!CFileStream::QueryInterface
    77f6b5ec  77fb34ed SHLWAPI!CAssocW2k::AddRef
    77f6b5f0  77f6b670 SHLWAPI!CFileStream::Release
    77f6b5f4  77f77474 SHLWAPI!CFileStream::Read
    0:000> .call SHLWAPI!CFileStream::Read(0x00131320, 0xa80000, 0x1000, 0)
                    ^ Symbol not a function in '.call SHLWAPI!CFileStream::Read'
    

    That error message is the debugger's somewhat confusing way of saying, "I don't have enough information available to make that function call." But that's okay, because we have a function that's "close enough", namely CAlphaStream::Read:

    0:001> .call ABC!CAlphaStream::Read(0x00131320, 0xa80000, 0x1000, 0)
    Thread is set up for call, 'g' will execute.
    WARNING: This can have serious side-effects,
    including deadlocks and corruption of the debuggee.
    0:000> r eip=SHLWAPI!CFileStream::Read
    0:000> r
    eax=00131320 ebx=0007d628 ecx=00130000 edx=0013239e esi=00000000 edi=00000003
    eip=77f77474 esp=0007d384 ebp=0007d3b0 iopl=0         nv up ei pl zr na po nc
    cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
    SHLWAPI!CFileStream::Read:
    77f77474 8bff             mov     edi,edi
    

    Woo-hoo! We got ABC!CAlphaStream::Read to push all the parameters for us, and then whoosh we swap out that function and slip CFileStream::Read in its place. Now you can hit "g" to execute the CFileStream::Read call.

    This just skims the surface of what you can do with the .call command. Mix in some C++ expression evaluation and you've got yourself a pretty nifty "pseudo-immediate mode" expression evaluator.

Page 1 of 4 (38 items) 1234