|
|
1.1 root 1:
2: Microsoft Foundation Classes Microsoft Corporation
3: Technical Notes
4:
5: #12 : Using MFC with Windows 3.1 Robustness Features
6:
7: Windows 3.1 is a major improvement over Windows 3.0 in the
8: area of robust application development. Windows 3.1 includes
9: a number of new features that enhance the reliability of a
10: Windows application. This technical note describes the
11: use of these features within the MFC library.
12:
13: =============================================================================
14:
15: Windows 3.1 Debug Kernel
16: ========================
17:
18: Testing your MFC application with the debug system executables is probably
19: the best thing you can do to make sure your applications are robust
20: and reliable. The debugging versions of the system executables perform all
21: sorts of useful error checking for you, informing you of any problems
22: that arise with debug output messages.
23:
24: The best way to use the debug system is with two machines: a machine for
25: testing and debugging that has the debug system installed, and a machine for
26: development. If you put a monochrome adapter card in your debug machine,
27: CodeView and debug system output can be directed to the monochrome monitor.
28:
29: But, not everyone can afford to buy a second machine just for debugging. One
30: drawback of installing the debug system on your development machine is that
31: it runs somewhat slower than the standard Windows system, so it slows down
32: your compiler, editor, and other debugging tools.
33:
34: A useful trick for single-machine debugging is to place copies of the system
35: and debug binaries and symbols in a separate directory, and have batch files
36: that copy the appropriate files to your Windows System directory. This way
37: you can exit Windows and switch back and forth quickly between debug and
38: non-debug. The SDK installation program will set this up for then you can
39: switch between debug and nondebug version of Windows with the D2N.BAT and
40: N2D.BAT batch files.
41:
42: If you aren't running with a debugger or a debug terminal, you should run the
43: DBWIN application so you can see the error and warning messages produced by
44: the debug system. This application is included with the SDK.
45:
46: Here are some common programming errors that appear more frequently than they
47: should in shipped Windows applications. Many of these problems can cause
48: random system UAEs and other problems under Windows 3.0. The debug system
49: binaries will help you track down these kinds of problems very quickly:
50:
51: * Passing invalid parameters of all shapes and sizes
52:
53: * Accessing nonexistent window words. In 3.0, a SetWindowWord or
54: SetWindowLong call past the end of the allocated window words (as
55: defined with RegisterClass) would trash internal window manager data
56: structures!
57:
58: * Using handles after they've been deleted or destroyed
59:
60: * Using a DC after it has been released
61:
62: * Deleting GDI objects before they're deselected from a DC
63:
64: * Forgetting to delete GDI bitmaps, brushes, pens, or other GDI
65: or USER objects when an application terminates
66:
67: * Writing past the end of an allocated memory block
68:
69: * Reading or writing through a memory pointer after it has been freed
70:
71: * Forgetting to export window procedures and other callbacks
72:
73: * Forgetting to use MakeProcInstance with dialog procs and other
74: callbacks (alternatively, you can use the MS C/C++ 7.0 feature
75: of marking these functions as EXPORT in their declaration.)
76:
77: * Shipping an app without running it with the debugging KERNEL, USER,
78: and GDI.
79:
80:
81: MFC Diagnostics
82: ===============
83:
84: In addition, the Microsoft Foundation Classes ship with a
85: set of robustness features that are compiled and linked only in the
86: debug build of the library (those library variants ending with a 'd'.)
87: Use of these features in the applications you write and in the
88: classes you design will greatly improve both the runtime and
89: compile time error trapping of your application. These functions
90: are outlined below, but all are documented in the Class Library
91: Reference manual.
92:
93: Every class in MFC includes a class invariant, AssertValid. This
94: member function is called to verify the "sanity" of a C++ object.
95: You call use this function whenever objects (or pointers or
96: references to objects) are passed as parameters. The macro
97: ASSERT_VALID(pObject) is supplied so that these calls are not
98: compiled for retail builds. Your class' implementation of this
99: function should first call the base class AssertValid explicitly
100: before doing any derived class specific validation.
101:
102: Parameter validation is another important feature. Aside from
103: validating objects, it is also important to validate buffers
104: and string constants. The global function AfxIsValidAddress should
105: be used to verify the validity of a buffer/length pair. The
106: Class Library Reference provides you with specific information
107: on this API.
108:
109: Every class in MFC implements a Dump member function, which
110: permits you to view the state of an object in an ASCII format. This
111: function can be called from CodeView or placed within #ifdef _DEBUG
112: /#endif portions of your code. You should supply a Dump member
113: for classes that you implement. As with AssertValid, you should
114: first explicitly call your base class Dump member function. The
115: output of Dump is routed to the "afxDump" CDumpContext which
116: by default goes to the CodeView output window or to your debug
117: terminal. You can also use the DBWIN program to view the output of
118: afxDump. The source file \C700\MFC\SRC\DUMPINIT.CPP includes information
119: on how to route afxDump to another destination.
120:
121: TRACE is a macro that behaves much like printf, only routes
122: output to the afxDump location. You should use TRACE statements
123: to indicate tricky or exceptional places in your code. As with
124: other robustness features, TRACE is only meaningful in the
125: debug library, and has no affect in the retail build. The MFC library
126: includes a number of built in TRACE statements for tracking the
127: flow of messages. Please see TN007.TXT for more information of
128: the debug trace information.
129:
130: ASSERT is a runtime check for the validity of a statement. You
131: should use ASSERTs liberally throughout your program. Any place
132: you have a comment to the affect:
133: /* lpStr should be NULL at this point */
134: you should replace that with a runtime assert:
135: ASSERT(lpStr == NULL);
136: The compiler cannot understand English, but it can execute
137: code! ASSERT statements have no affect in retails builds. If
138: you need the side effects of an ASSERT to occur in the retail build
139: as well, then use the VERIFY macro.
140:
141: MFC also includes an extensive diagnostic memory allocator. You
142: diagnostic memory allocator to make sure that you free all memory
143: resources before your program exits. The diagnostic
144: allocator will track the source file and line number of an
145: allocation, so if you use the CMemoryState::DumpAllObjectsSince
146: API you can locate any remaining allocations. A good place to
147: use this API is in the ExitInstance member function of CWinApp
148: (which you can override, but be sure to call the base class
149: ExitInstance.) Additionally, if you have a rather tricky piece
150: of code that does lots of allocations and deallocations, you can
151: use the CMemoryState::Checkpoint and CMemoryState::Difference
152: APIs to be sure to leave the world in a steady state after
153: executing such code.
154:
155:
156: Windows 3.1 STRICT type checking
157: ================================
158:
159: STRICT type checking is an option available with the new
160: WINDOWS.H header file. Before a discussion of the use
161: of STRICT, a brief description of C++ typesafe linkage is
162: in order.
163:
164: In C++ you are permitted to have many functions with the
165: same name, so long as these functions have different formal
166: parameter lists. In order to have unique link symbols, the
167: C++ compiler will "decorate" these names using an algorithm
168: that encodes information about a function such as the name,
169: number and type of formal parameters, calling convention, etc.
170: This newly generated name is used as the external link symbol
171: for the function. This is known as typesafe linkage and is a
172: big benefit of C++. This name decoration does not apply to
173: functions within an extern "C" block, and is why all APIs in
174: WINDOWS.H are in such a block.
175:
176: STRICT typechecking in WINDOWS.H attempts to imitate C++ type
177: safety for C by using distinct types to represent all the different
178: HANDLES in Windows. So for example, STRICT prevents you from
179: mistakenly passing an HPEN to a routine expecting an HBITMAP.
180: Since the Windows APIs are all within extern "C" { } blocks,
181: they are not decorated in the manner described above. STRICT
182: plays tricks with the C compiler by changing the types of
183: the various Windows typedefs to make them unique (specifically
184: it uses different pointer types to represent HANDLEs, which cannot
185: be freely converted without an explicit cast.)
186:
187: As you can see, if you have STRICT typechecking enabled in
188: one file, but not in another, the C++ compiler will generate
189: different external link symbols for a single function. This
190: will result in link time errors. Therefore, it is recommended
191: that you use STRICT typechecking only for C modules (those that
192: end in .C). Additionally, STRICT is a compile time only
193: option, so once you sucessfully compile your code the benefits
194: of STRICT are completely realized.
195:
196: MFC accomplishes all of STRICT static typechecking, plus a whole
197: lot more, by using the C++ language. Therefore, STRICT is disabled
198: by default. If you wish to use STRICT you will need to recompile
199: the MFC libraries that you regularly use (because of typesafe
200: linkage, the external link symbols are different between STRICT
201: and non-STRICT.)
202:
203: The following are guidelines for using STRICT with C/C++/MFC.
204:
205: If you have existing Windows 3.0 C code and you wish to keep it as C code,
206: you can either work to make it STRICT compliant or not, that option is
207: yours. Be sure to use C++ conventions for your exported header file
208: such as putting extern "C" { } around your C APIs if you intend on
209: using the header file within any C++ code. If you have existing Windows
210: 3.1 STRICT C code, then moving it to C++/MFC eliminates the need for
211: STRICT.
212:
213: For any C code that you have, the use of STRICT is optional
214: and encouraged. For C++ code, you should use STRICT with
215: great care, if at all, because of the issues of typesafe linkage.
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.