| Introduction |
xxiii |
| PART I REQUIRED READING |
|
| CHAPTER ONE Error Handling |
3 |
| You Can Do This Too |
8 |
| The ErrorShow Sample Application |
9 |
| CHAPTER TWO Unicode |
17 |
| Character Sets |
17 |
| Single-Byte and Double-Byte Character Sets |
18 |
| Unicode:The Wide-Byte Character Set |
18 |
| Why You Should Use Unicode |
20 |
| Windows 2000 and Unicode |
20 |
| Windows 98 and Unicode |
21 |
| Windows CE and Unicode |
22 |
| Keeping Score |
22 |
| A Quick Word About COM |
22 |
| How to Write Unicode Source Code |
23 |
| Unicode Support in the C Run-Time Library |
23 |
| Unicode Data Types Defined by Windows |
26 |
| Unicode and ANSI Functions in Windows |
26 |
| Windows String Functions |
28 |
| Making Your Application ANSI- and Unicode-Ready |
29 |
| Windows String Functions |
30 |
| Resources |
33 |
| Determining If Text Is ANSI or Unicode |
34 |
| Translating Strings Between Unicode and ANSI |
35 |
| CHAPTER THREE Kernel Objects |
41 |
| What Is a Kernel Object? |
41 |
| Usage Counting |
42 |
| Security |
43 |
| A Process's Kernel Object Handle Table |
46 |
| Creating a Kernel Object |
46 |
| Closing a Kernel Object |
48 |
| Sharing Kernel Objects Across Process Boundaries |
49 |
| Object Handle Inheritance |
50 |
| Named Objects |
55 |
| Duplicating Object Handles |
60 |
| PART II GETTING WORK DONE |
|
| CHAPTER FOUR Processes |
69 |
| Writing Your First Windows Application |
71 |
| A Process's Instance Handle |
76 |
| A Process's Previous Instance Handle |
77 |
| A Process's Command Line |
78 |
| A Process's Environment Variables |
79 |
| A Process's Affinity |
83 |
| A Process's Error Mode |
83 |
| A Process's Current Drive and Directory |
84 |
| The System Version |
86 |
| The CreateProcess Function |
90 |
| pszApplicationName and pszCommandLine |
91 |
| psaProcess, psaThread, and bInheritHandles |
94 |
| fdwCreate |
96 |
| pvEnvironment |
99 |
| pszCurDir |
100 |
| psiStartInfo |
100 |
| ppiProcInfo |
105 |
| Terminating a Process |
107 |
| The Primary Thread's Entry-Point Function Returns |
107 |
| The ExitProcess Function |
108 |
| The TerminateProcess Function |
110 |
| When All the Threads in the Process Die |
110 |
| When a Process Terminates |
111 |
| Child Processes |
112 |
| Running Detached Child Processes |
114 |
| Enumerating the Processes Running in the System |
114 |
| The Process Information Sample Application |
115 |
| CHAPTER FIVE Jobs |
137 |
| Placing Restrictions on a Job's Processes |
140 |
| Placing a Process in a Job |
149 |
| Terminating All Processes in a Job |
150 |
| Querying Job Statistics |
151 |
| Job Notifications |
155 |
| The JobLab Sample Application |
158 |
| CHAPTER SIX Thread Basics |
181 |
| When to Create a Thread |
182 |
| When Not to Create a Thread |
184 |
| Writing Your First Thread Function |
185 |
| The CreateThread Function |
186 |
| psa |
187 |
| cbStack |
187 |
| pfnStartAddr and pvParam |
188 |
| fdwCreate |
190 |
| pdwThreadID |
190 |
| Terminating a Thread |
191 |
| The Thread Function Returns |
191 |
| The ExitThread Function |
191 |
| The TerminateThread Function |
192 |
| When a Process Terminates |
193 |
| When a Thread Terminates |
193 |
| Some Thread Internals |
194 |
| C/C++ Run-Time Library Considerations |
198 |
| Oops—I Called CreateThread Instead of _beginthreadex by Mistake |
208 |
| C/C++ Run-Time Library Functions That You Should Never Call |
208 |
| Gaining a Sense of One's Own Identity |
209 |
| Converting a Pseudo-Handle to a Real Handle |
210 |
| CHAPTER SEVEN Thread Scheduling, Priorities, and Affinities |
213 |
| Suspending and Resuming a Thread |
215 |
| Suspending and Resuming a Process |
216 |
| Sleeping |
218 |
| Switching to Another Thread |
219 |
| A Thread's Execution Times |
219 |
| Putting the Context in Context |
223 |
| Thread Priorities |
228 |
| An Abstract View of Priorities |
230 |
| Programming Priorities |
235 |
| Dynamically Boosting Thread Priority Levels |
238 |
| Tweaking the Scheduler for the Foreground Process |
240 |
| The Scheduling Lab Sample Application |
241 |
| Affinities |
250 |
| CHAPTER EIGHT Thread Synchronization in User Mode |
257 |
| Atomic Access: The Interlocked Family of Functions |
258 |
| Cache Lines |
265 |
| Advanced Thread Synchronization |
267 |
| A Technique to Avoid |
268 |
| Critical Sections |
269 |
| Critical Sections:The Fine Print |
273 |
| Critical Sections and Spinlocks |
277 |
| Critical Sections and Error Handling |
278 |
| Useful Tips and Techniques |
279 |
| CHAPTER NINE Thread Synchronization with Kernel Objects |
285 |
| Wait Functions |
287 |
| Successful Wait Side Effects |
291 |
| Event Kernel Objects |
293 |
| The Handshake Sample Application |
297 |
| Waitable Timer Kernel Objects |
305 |
| Having Waitable Timers Queue APC Entries |
309 |
| Timer Loose Ends |
312 |
| Semaphore Kernel Objects |
313 |
| Mutex Kernel Objects |
315 |
| Abandonment Issues |
317 |
| Mutexes vs. Critical Sections |
318 |
| The Queue Sample Application |
319 |
| A Handy Thread Synchronization Object Chart |
331 |
| Other Thread Synchronization Functions |
332 |
| Asynchronous Device I/O |
332 |
| WaitForInputIdle |
332 |
| MsgWaitForMultipleObjects(Ex) |
333 |
| WaitForDebugEvent |
334 |
| SignalObjectAndWait |
334 |
| CHAPTER TEN Thread Synchronization Toolkit |
337 |
| Implementing a Critical Section: The Optex |
337 |
| The Optex Sample Application |
340 |
| Creating Thread-Safe Datatypes and Inverse Semaphores |
353 |
| The InterlockedType Sample Application |
358 |
| The Single Writer/Multiple Reader Guard (SWMRG) |
368 |
| The SWMRG Sample Application |
371 |
| Implementing a WaitForMultipleExpressions Function |
380 |
| The WaitForMultipleExpressions Sample Application |
382 |
| CHAPTER ELEVEN Thread Pooling |
399 |
| Scenario 1:Call Functions Asynchronously |
401 |
| Scenario 2:Call Functions at Timed Intervals |
403 |
| The TimedMsgBox Sample Application |
407 |
| Scenario 3:Call Functions When Single Kernel Objects Become Signaled |
412 |
| Scenario 4:Call Functions When Asynchronous I/O Requests Complete |
415 |
| CHAPTER TWELVE Fibers |
417 |
| Working with Fibers |
417 |
| The Counter Sample Application |
421 |
| PART III MEMORY MANAGEMENT |
|
| CHAPTER THIRTEEN Windows Memory Architecture |
435 |
| A Process's Virtual Address Space |
435 |
| How a Virtual Address Space Is Partitioned |
436 |
| Null-Pointer Assignment Partition (Windows 2000 and Windows 98) |
438 |
| MS-DOS/16-Bit Windows Application Compatibility Partition (Windows 98 Only) |
438 |
| User-Mode Partition (Windows 2000 and Windows 98) |
439 |
| 64-KB Off-Limits Partition (Windows 2000 Only) |
441 |
| Shared MMF Partition (Windows 98 Only) |
442 |
| Kernel-Mode Partition (Windows 2000 and Windows 98) |
442 |
| Regions in an Address Space |
443 |
| Committing Physical Storage Within a Region |
444 |
| Physical Storage and the Paging File |
444 |
| Physical Storage Not Maintained in the Paging File |
447 |
| Protection Attributes |
449 |
| Copy-On-Write Access |
450 |
| Special Access Protection Attribute Flags |
452 |
| Bringing It All Home |
452 |
| Inside the Regions |
456 |
| Address Space Differences for Windows 98 |
461 |
| The Importance of Data Alignment |
465 |
| CHAPTER FOURTEEN Exploring Virtual Memory |
471 |
| System Information |
471 |
| The System Information Sample Application |
473 |
| Virtual Memory Status |
481 |
| The Virtual Memory Status Sample Application |
483 |
| Determining the State of an Address Space |
489 |
| The VMQuery Function |
490 |
| The Virtual Memory Map Sample Application |
499 |
| CHAPTER FIFTEEN Using Virtual Memory in Your Own Applications |
513 |
| Reserving a Region in an Address Space |
513 |
| Committing Storage in a Reserved Region |
516 |
| Reserving a Region and Committing Storage Simultaneously |
517 |
| When to Commit Physical Storage |
518 |
| Decommitting Physical Storage and Releasing a Region |
520 |
| When to Decommit Physical Storage |
521 |
| The Virtual Memory Allocation Sample Application |
523 |
| Changing Protection Attributes |
534 |
| Resetting the Contents of Physical Storage |
536 |
| The MemReset Sample Application |
537 |
| Address Windowing Extensions (Windows 2000 only) |
540 |
| The AWE Sample Application |
546 |
| CHAPTER SIXTEEN A Thread's Stack |
559 |
| A Thread's Stack Under Windows 98 |
563 |
| The C/C++ Run-Time Library's Stack-Checking Function |
565 |
| The Summation Sample Application |
567 |
| CHAPTER SEVENTEEN Memory-mapped Files |
577 |
| Memory-Mapped Executables and DLLs |
578 |
| Static Data Is Not Shared by Multiple Instances of an Executable or a DLL |
579 |
| Sharing Static Data Across Multiple Instances of an Executable or a DLL |
582 |
| The AppInst Sample Application |
588 |
| Memory-Mapped Data Files |
594 |
| Method 1: One File, One Buffer |
595 |
| Method 2: Two Files, One Buffer |
595 |
| Method 3: One File, Two Buffers |
596 |
| Method 4: One File, Zero Buffers |
596 |
| Using Memory-Mapped Files |
597 |
| Step 1: Creating or Opening a File Kernel Object |
597 |
| Step 2: Creating a File-Mapping Kernel Object |
599 |
| Step 3: Mapping the File's Data into the Process's Address Space |
603 |
| Step 4: Unmapping the File's Data from the Process's Address Space |
606 |
| Steps 5 and 6: Closing the File-Mapping Object and the File Object |
608 |
| The File Reverse Sample Application |
609 |
| Processing a Big File Using Memory-Mapped Files |
620 |
| Memory-Mapped Files and Coherence |
621 |
| Specifying the Base Address of a Memory-Mapped File |
622 |
| Implementation Details of Memory-Mapped Files |
624 |
| Using Memory-Mapped Files to Share Data Among Processes |
627 |
| Memory-Mapped Files Backed by the Paging File |
628 |
| The Memory-Mapped File Sharing Sample Application |
630 |
| Sparsely Committed Memory-Mapped Files |
636 |
| The Sparse Memory-Mapped File Sample Application |
638 |
| CHAPTER EIGHTEEN Heaps |
655 |
| A Process's Default Heap |
656 |
| Reasons to Create Additional Heaps |
657 |
| Component Protection |
657 |
| More Efficient Memory Management |
658 |
| Local Access |
659 |
| Avoiding Thread Synchronization Overhead |
660 |
| Quick Free |
660 |
| How to Create an Additional Heap |
660 |
| Allocating a Block of Memory from a Heap |
662 |
| Changing the Size of a Block |
664 |
| Obtaining the Size of a Block |
665 |
| Freeing a Block |
665 |
| Destroying a Heap |
665 |
| Using Heaps with C++ |
666 |
| Miscellaneous Heap Functions |
670 |
| PART IV DYNAMIC-LINK LIBRARIES |
|
| CHAPTER NINETEEN DLL Basics |
675 |
| DLLs and a Process's Address Space |
677 |
| The Overall Picture |
679 |
| Building the DLL Module |
683 |
| What Exporting Really Means |
685 |
| Creating DLLs for Use with Non_Visual C++ Tools |
688 |
| Building the Executable Module |
689 |
| What Importing Really Means |
690 |
| Running the Executable Module |
692 |
| CHAPTER TWENTY DLL Advanced Techniques |
695 |
| Explicit DLL Module Loading and Symbol Linking |
695 |
| Explicitly Loading the DLL Module |
697 |
| Explicitly Unloading the DLL Module |
698 |
| Explicitly Linking to an Exported Symbol |
701 |
| The DLL's Entry-Point Function |
702 |
| The DLL_PROCESS_ATTACH Notification |
703 |
| The DLL_PROCESS_DETACH Notification |
705 |
| The DLL_THREAD_ATTACH Notification |
707 |
| The DLL_THREAD_DETACH Notification |
708 |
| Serialized Calls to DllMain |
709 |
| DllMain and the C/C++ Run-Time Library |
712 |
| Delay-Loading a DLL |
714 |
| The DelayLoadApp Sample Application |
719 |
| Function Forwarders |
727 |
| Known DLLs |
728 |
| DLL Redirection |
729 |
| Rebasing Modules |
730 |
| Binding Modules |
738 |
| CHAPTER TWENTY-ONE Thread-Local Storage |
743 |
| Dynamic TLS |
744 |
| Using Dynamic TLS |
747 |
| Static TLS |
749 |
| CHAPTER TWENTY-TWO DLL INJECTION AND API HOOKING |
751 |
| DLL Injection: An Example |
752 |
| Injecting a DLL Using the Registry |
754 |
| Injecting a DLL Using Windows Hooks |
757 |
| The Desktop Item Position Saver (DIPS) Utility |
759 |
| Injecting a DLL Using Remote Threads |
774 |
| The Inject Library Sample Application |
779 |
| The Image Walk DLL |
789 |
| Injecting a DLL with a Trojan DLL |
792 |
| Injecting a DLL as a Debugger |
793 |
| Injecting Code with a Memory-Mapped File on Windows 98 |
793 |
| Injecting Code with CreateProcess |
794 |
| API Hooking: An Example |
795 |
| API Hooking by Overwriting Code |
796 |
| API Hooking by Manipulating a Module's Import Section |
797 |
| The LastMsgBoxInfo Sample Application |
801 |
| PART V STRUCTURED EXCEPTION HANDLING |
|
| CHAPTER TWENTY-THREE Termination Handlers |
823 |
| Understanding Termination Handlers by Example |
825 |
| Funcenstein1 |
825 |
| Funcenstein2 |
826 |
| Funcenstein3 |
828 |
| Funcfurter1 |
829 |
| Pop Quiz Time: FuncaDoodleDoo |
830 |
| Funcenstein4 |
831 |
| Funcarama1 |
832 |
| Funcarama2 |
833 |
| Funcarama3 |
834 |
| Funcarama4: The Final Frontier |
835 |
| Notes About the finally Block |
837 |
| Funcfurter2 |
838 |
| The SEH Termination Sample Application |
839 |
| CHAPTER TWENTY-FOUR Exception Handlers and Software Exceptions |
843 |
| Understanding Exception Filters and Exception Handlers by Example |
844 |
| Funcmeister1 |
844 |
| Funcmeister2 |
845 |
| EXCEPTION_EXECUTE_HANDLER |
847 |
| Some Useful Examples |
848 |
| Global Unwinds |
851 |
| Halting Global Unwinds |
855 |
| EXCEPTION_CONTINUE_EXECUTION |
856 |
| Use EXCEPTION_CONTINUE_EXECUTION with Caution |
857 |
| EXCEPTION_CONTINUE_SEARCH |
858 |
| GetExceptionCode |
861 |
| Memory-Related Exceptions |
861 |
| Exception-Related Exceptions |
862 |
| Debugging-Related Exceptions |
862 |
| Integer-Related Exceptions |
862 |
| Floating Point_Related Exceptions |
863 |
| GetExceptionInformation |
866 |
| Software Exceptions |
870 |
| CHAPTER TWENTY-FIVE Unhandled Exceptions and C++ Exceptions |
875 |
| Just-In-Time Debugging |
878 |
| Turning Off the Exception Message Box |
880 |
| Forcing the Process to Die |
880 |
| Wrapping a Thread Function |
880 |
| Wrapping All Thread Functions |
881 |
| Automatically Invoking the Debugger |
882 |
| Calling UnhandledExceptionFilter Yourself |
882 |
| Inside the UnhandledExceptionFilter Function |
883 |
| Exceptions and the Debugger |
885 |
| The Spreadsheet Sample Application |
889 |
| C++ Exceptions Versus Structured Exceptions |
904 |
| Catching Structured Exceptions with C++ |
906 |
| PART VI WINDOWING |
|
| CHAPTER TWENTY-SIX Window Messaging |
911 |
| A Thread's Message Queue |
912 |
| Posting Messages to a Thread's Message Queue |
914 |
| Sending Messages to a Window |
915 |
| Waking a Thread |
922 |
| The Queue Status Flags |
923 |
| The Algorithm for Extracting Messages from a Thread's Queue |
925 |
| Waking a Thread with Kernel Objects or with Queue Status Flags |
928 |
| Sending Data with Messages |
932 |
| The CopyData Sample Application |
935 |
| How Windows Handle ANSI/Unicode Characters and Strings |
941 |
| CHAPTER TWENTY-SEVEN The Hardware Input Model and Local Input State |
945 |
| The Raw Input Thread |
945 |
| Local Input State |
947 |
| Keyboard Input and Focus |
948 |
| Mouse Cursor Management |
953 |
| Attaching Virtualized Input Queues and Local Input State Together |
955 |
| The Local Input State Laboratory (LISLab) Sample Application |
957 |
| The Local Input State Watch (LISWatch) Sample Application |
978 |
| APPENDIX A The Build Environment |
989 |
| The CmnHdr.h Header File |
989 |
| Windows Version Build Option |
990 |
| Unicode Build Option |
990 |
| Windows Definitions and Warning Level 4 |
991 |
| The Pragma Message Helper Macro |
991 |
| The chINRANGE and chDIMOF Macros |
992 |
| The chBEGINTHREADEX Macro |
992 |
| DebugBreak Improvement for x86 Platforms |
994 |
| Creating Software Exception Codes |
994 |
| The chMB Macro |
995 |
| The chASSERT and chVERIFY Macros |
995 |
| The chHANDLE_DLGMSG Macro |
995 |
| The chSETDLGICONS Macro |
995 |
| The OS Version Check Inline Functions |
995 |
| Making Sure the Host System Supports Unicode |
996 |
| Forcing the Linker to Look for a (w)WinMain Entry-Point Function |
996 |
| APPENDIX B Message Crackers, Child Control Macros, and API Macros |
1005 |
| Message Crackers |
1006 |
| Child Control Macros |
1009 |
| API Macros |
1010 |
| Index |
1011 |