Holy cow, I wrote a book!
A customer asked,
Is there a way to turn off Full Window Drag on a single window? I have a resizable control that I would like not update itself while resizing.
It so happens that I wrote a sample program ages ago to illustrate how to do this. You can find it in the Platform SDK under winui\fulldrag. The source code is also reproduced in this Knowledge Base article.
winui\fulldrag
In addition to deferring painting, you may also want to defer layout if layout is expensive for your window.
The Grammy Awards will be handed out this upcoming weekend, an annual award that seems to have survived.
A not uncommon phenomenon at Microsoft is the annual award that winds up being awarded only once. Because all the excitement is in the announcement, not in the actual award.
Every year, we want to uniquely call out and recognize a set of people. I'm proud to kick off the XYZ Awards, which we will be given every year, starting this year, which recognize employees who best represent ABC and DEF.
The XYZ Awards were indeed handed out that first year with great pomp and circumstance.
And were never heard from again.
This is a special case of the more general phenomenon of the introduction of some undertaking to great fanfare, only to have it quietly fade away into obscurity without any formal announcement that it had ended. One might cynically observe that the likelihood of this happening to your project increases the more dramatically it is introduced. If it's just called a program, then it might survive. If it's called an initiative, then you might want to hold off on ordering new business cards for a while. And if it's called a bold new initiative, then you'll want to spend some time freshening your résumé, because your project is doomed.
Update since people seem to be missing the point: I'm not talking about marketing campaigns. Those are meant to die out eventually. I'm talking about stuff like The Council for Programming Excellence (which meets only once) or The DTI Program (which has a kickoff meeting and then nothing).
There seemed to be a great deal of disbelief that anybody would hard-code the path to Notepad.
Here's one example and here's another.
There's a large class of problems that go like this:
I'm running Program X, and when I tell it to view the error log, I get this error message: CreateProcess of "C:\Windows\Notepad.exe errorlog.txt" failed: error 2: The system cannot find the file specified. What is wrong and how do I fix it?
CreateProcess of "C:\Windows\Notepad.exe errorlog.txt" failed: error 2: The system cannot find the file specified.
Obviously, the file C:\Windows\Notepad.exe is missing. But how can that be? Well, Windows Server 2008 bit the bullet and removed one of the copies of Notepad. Once you learn this, troubleshooting the above problem becomes a simple exercise in psychic debugging.
C:\Windows\Notepad.exe
My psychic powers tell me that you're running Windows Server 2008. The Notepad program no longer exists in the Windows directory; it's now in the system directory. Find the setting for your program that lets you change the program used for viewing error logs and tell it to use C:\Windows\System32\Notepad.exe.
C:\Windows\System32\Notepad.exe
Of course, this tip works only if the program permits you to change the program used for viewing error logs. If they hard-code the path, then you'll have to find some other workaround. (For example, you might try using the CorrectFilePaths shim.)
A customer had a debug trace log and needed some help interpreting it. The trace log was generated by an operating system component, but the details aren't important to the story.
I've attached the log file. I think the following may be part of the problem. [07/17/2005:18:31:19] Creating process D:\Foo\bar\blaz.exe [07/17/2005:18:31:19] CreateProcess failed with error 2 Any ideas? Thanks, Bob Smith Senior Test Engineer Tailspin Toys
I've attached the log file. I think the following may be part of the problem.
[07/17/2005:18:31:19] Creating process D:\Foo\bar\blaz.exe [07/17/2005:18:31:19] CreateProcess failed with error 2
Any ideas?
Thanks, Bob Smith Senior Test Engineer Tailspin Toys
What struck me is that Bob is proud of the fact that he's a Senior Test Engineer, perhaps because it makes him think that we will take him more seriously because he has some awesome title.
But apparently a Senior Test Engineer doesn't know what error 2 is. There are some error codes that you end up committing to memory because you run into them over and over. Error 32 is ERROR_SHARING_VIOLATION, error 3 is ERROR_PATH_NOT_FOUND, and in this case, error 2 is ERROR_FILE_NOT_FOUND.
ERROR_SHARING_VIOLATION
ERROR_PATH_NOT_FOUND
ERROR_FILE_NOT_FOUND
And even if Bob didn't have error 2 memorized, he should have known to look it up.
Error 2 is ERROR_FILE_NOT_FOUND. Does the file D:\Foo\bar\blaz.exe exist?
D:\Foo\bar\blaz.exe
No, it doesn't. -Bob
No, it doesn't.
-Bob
Bob seems to have shut off his brain and decided to treat troubleshooting not as a collaborative effort but rather as a game of Twenty Questions in which the person with the problem volunteers as little information as possible in order to make things more challenging. I had to give Bob a nudge.
Can you think of a reason why the system would be looking at D:\Foo\bar\blaz.exe? Where did you expect it to be looking for blaz.exe?
blaz.exe
This managed to wake Bob out of his stupor, and the investigation continued. (And no, I don't remember what the final resolution was. I didn't realize I would have to remember the fine details of this support incident three years later.)
You may hear an old-timer developer use the verb zap.
That proposed fix will work. Until everybody gets the fix, they can just zap the assert.
The verb to zap means to replace a breakpoint instruction with an appropriate number of NOP instructions (effectively ignoring it).
The name comes from the old Windows 2.x kernel debugger. (Actually, it may be even older, but that's as far back as I was able to trace it.) The Z (zap) command replaces the current instruction with a NOP if it is an int 3 (the x86 single-byte breakpoint instruction), or replaced the previous instruction with NOPs if it is an int 1 (the x86 two-byte breakpoint instruction).
Z
int 3
int 1
This operation was quite common back in the days when lots of code was written in assembly language. A technique used by some teams was to insert a hard-coded breakpoint (called a TRAP) into every code path of a function. Here's an example (with comments and other identifying characteristics removed and new ones made up):
TRAP
xyz8: mov bl,[eax].xyz_State cmp bl,XYZSTATE_IGNORE TRAPe je short xyz10 ; ignore this one or bl,bl TRAPe je short xyz11 ; end of table mov bh,[eax].xyz_Flags test bh,XYZFLAGS_HIDDEN TRAPz jz short xyz10 ; skip - item is hidden test bh,XYZFLAGS_MAGIC TRAPe je short gvl10 ; skip - not the magic item TRAP bts [esi].alt_flags,ALTFLAGS_SEENMAGIC TRAPc jc short xyz10 ; weird - we shouldn't have two magic items
There were a variety of TRAP macros. Here we see the one plain vanilla TRAP and a bunch of fancy traps which trigger only when certain conditions are met. For example, TRAPc traps if the carry is set. Here's its definition:
TRAPc
TRAPc MACRO local l jnc short l int 3 l: ENDM
Hardly rocket science.
When you became the person to trigger a particular code path for the first time, you would trigger the trap, and you either stepped through the code yourself or (if you weren't familiar with the code) contacted the author of the code to verify that the code successfully handled this "never seen before" case. When sufficiently satisfied that a code path operated as expected, the developer removed the corresponding TRAP from the source code.
Of course, most TRAPs are removed before the code gets checked in, but the ones related to error handling or recovering from data corruption tend to remain (such as here, where we inserted a TRAP when we encounter two magic items, which is theoretically impossible).
When you trigger one trap, you usually trigger it a lot, and you usually trigger a lot of related traps as well. The Z command was quite handy at neutering each one after you checked that everything was working. You zapped the trap.
That's why old-timers refer to patching out a hard-coded breakpoint as zapping, even though the zap command hasn't existed for over a decade.
Update: As far as I can tell, the earlier uses of the word zap referred to patching binaries, not for removing hard-coded breakpoints after they stopped in the debugger.
Jonathan Wilson asks why the clipboard APIs still require GlobalAlloc and friends. Why is there not a SetClipboardDataEx or something that does what SetClipboardData does but without needing to call GlobalAlloc?
SetClipboardDataEx
SetClipboardData
GlobalAlloc
Okay, here's your function:
HANDLE SetClipboardDataEx(UINT uFormat, void *pvData, DWORD cbData) { if (uFormat == CF_BITMAP || uFormat == CF_DSPBITMAP || uFormat == CF_PALETTE || uFormat == CF_METAFILEPICT || uFormat == CF_DSPMETAFILEPICT || uFormat == CF_ENHMETAFILE || uFormat == CF_DSPENHMETAFILE || uFormat == CF_OWNERDISPLAY) { return NULL; // these are not HGLOBAL format } HANDLE hRc = NULL; HGLOBAL hglob = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE | GMEM_ZEROINIT, cbData); if (hglob) { void *pvGlob = GlobalLock(hglob); if (pvGlob) { CopyMemory(pvGlob, pvData, cbData); GlobalUnlock(hglob); hRc = SetClipboardData(uFormat, hglob); } if (!hRc) { GlobalFree(hglob); } } return hRc; }
Whoop-dee-doo.
Historically, Windows doesn't go out of its way to include functions like this because you can easily write them yourself, or you can at least find a framework library that did it for you. Windows focused on doing the things that only Windows could do, providing you the building blocks with which you can create your own programs.
Besides, the classic clipboard is so old-school. The OLE clipboard provides a much richer interface, where you can generate data dynamically (for example as a stream) and expose it in formats other than just a chunk of bytes. Since SetClipboardData is old-school, if the window manager folks had written a function like SetClipboardDataEx, people would instead have asked the not unreasonable question, "Why did you bother to write a function that provides no essential new functionality to an old interface that was supplanted over a decade ago?"
It turns out that my quick overview of how processes exit on Windows XP was already out of date when I wrote it. Mind you, the information is still accurate for Windows XP (as far as I know), but the rules changed in Windows Vista.
What about critical sections? There is no "Uh-oh" return value for critical sections; EnterCriticalSection doesn't have a return value. Instead, the kernel just says "Open season on critical sections!" I get the mental image of all the gates in a parking garage just opening up and letting anybody in and out.
EnterCriticalSection
In Windows Vista, the gates don't go up. Instead they become electrified!
If during DLL_PROCESS_DETACH at process termination on Windows Vista you call EnterCriticalSection on a critical section that has been orphaned, the kernel no longer responds by just letting you through. Instead, it says, "Oh dear, things are in unrecoverably bad shape. Best to just terminate the process now." If you try to enter an orphaned critical section during process shutdown, the kernel simply calls TerminateProcess on the current process!
DLL_PROCESS_DETACH
TerminateProcess
It's sort of like the movie Speed: If the thread encounters a critical section that causes it to drop below 50 miles per hour, it blows up.
Fortunately, this error doesn't change the underlying analysis of How my lack of understanding of how processes exit on Windows XP forced a security patch to be recalled.
But it also illustrates how the details of process shutdown are open to changes in the implementation at any time, so you shouldn't rely on them. Remember the classical model for how processes exit: You cleanly shut down all your worker threads, and then call ExitProcess. If you don't follow that model (and given the current programming landscape, you pretty have no choice but to abandon that model, what with DLLs creating worker threads behind your back), it's even more important that you follow the general guidance of not doing anything scary in your DllMain function.
ExitProcess
DllMain
Back in the old days, programmers were assumed to be smart and hardworking. Windows didn't provide functions for things that programs could already do on their own. Windows worried about providing functionality for thing that programs couldn't do. That was the traditional separation of responsibilities in operating systems of that era. If you wanted somebody to help you with stuff you could in principle do yourself, you could use a runtime library or a programming framework.
You know how to open files, read them, and write to them; therefore, you could write your own file copy function. You know how to walk a linked list; the operating system didn't provide a linked list management library. There are apparently some people who think that it's the job of an operating system to alleviate the need for implementing them yourself; actually that's the job of a programming framework or tools library. Windows doesn't come with a finite element analysis library either.
You can muse all you want about how things would have been better if Windows had had an installer library built-in from the start or even blame Windows for having been released without one, but then again, the core unix operating system doesn't have an application installer library either. The unix kernel has functions for manipulating the file system and requesting memory from the operating system. Standards for installing applications didn't arrive until decades later. And even though such standards exist today (as they do in Windows), there's no law of physics preventing a vendor from writing their own installation program that doesn't adhere to those standards and which can do anything they want to the system during install. After all, at the end of the day, installing an application's files is just calling creat and write with the right arguments.
creat
write
Commenter Archangel remarks, "At least if the ACL route had been taken, the installers would have had to be fixed - and fixed they would have been, when the vendors realised they didn't run on XP."
These arguments remind me of the infamous "Step 3: Profit" business plan of the Underpants Gnomes.
It's that step 2 that's the killer. Because the unwritten step 2 is "All applications stop working until the vendors fix them."
Who's going to fix the the bill-printing system that a twelve-year-old kid wrote over a decade ago, but which you still use to run your business. (I'm not making this up.) What about that shareware program you downloaded three years ago? And it's not just software where the authors are no longer available. The authors may simply not have the resources to go back and update every single program that they released over the past twenty years. There are organizations with thousands of install scripts which are used to deploy their line-of-business applications. Even if they could fix ten scripts a day, it'd take them three years before they could even start thinking about upgrading to the next version of Windows. (And what about those 16-bit applications? Will they have to be rewritten as 32-bit applications? How long will that take? Is there even anybody still around who understands 16-bit Windows enough to be able to undertake the port?)
A colleague of mine showed me some code from a back-end program on a web server. Fortunately, the company that wrote this is out of business. Or at least I hope they're out of business!
size = 16384; while (size && IsBadReadPtr(buffer, size)) { size--; }
Many years ago, I happened to have lunch with one of the programmers who worked on the video game Monty Python's Complete Waste of Time (read a review). This program was notable in many ways, most geekily that it was brought on board the Mir space station by astronaut Michael Foale.
Anyway, during the course of lunch, I learned something unusual:
"The hardest part of writing that program? Synchronizing the farts [sounds] to the video."
Not really related: Trailer for IMAX Hubble 3D movie.