ID: Q105372
1.00 WINDOWS kbprg kbfixlist kbbuglist
The information in this article applies to:
- Microsoft Visual C++ for Windows, version 1.0
When using one of the map classes (for example, CMapStringToOb) and iterating through the map in a retail build of an _AFXDLL application, a general protection (GP) fault occurs in GetNextAssoc(). A debug build of the same application, or a non-AFXDLL version (debug or retail), does not cause a GP fault.
GetStartPosition() returns the predefined value BEFORE_START_POSITION, which is defined incorrectly in AFX.H. GetNextAssoc() does not identify this as the beginning of the map and incorrectly uses this value as a pointer.
Because an _AFXDLL application makes use of MFC200.DLL, it is insufficient to correct the definition of BEFORE_START_POSITION and rebuild the application. MFC200.DLL contains references to BEFORE_START_POSITION that were set at compile time (of the DLL), and therefore changing the definition without also rebuilding MFC200.DLL will not solve the problem. Microsoft does not recommend shipping modified versions of MFC200.DLL with applications.
To work around the problem, derive a new map class and override GetNextAssoc() by copying the code from the appropriate MAP_XX.CPP file in ~\MFC\SRC. No changes to the code are necessary, and it is not necessary to correct the definition of BEFORE_START_POSITION. Use the new map class in place of the original.
Microsoft has confirmed this to be a problem with version 2.0 of the Microsoft Foundation Classes for Windows. This problem was corrected in MFC 2.5.
In AFX.H, BEFORE_START_POSITION is defined as:
#define BEFORE_START_POSITION ((void*)(void NEAR*)-1)
The explicit NEAR cast in this definition combined with the large
memory model (required by _AFXDLL) causes this to evaluate to DS:-1.
The correct definition should be ((void*)-1), which does not depend on
DS.
In a retail build, GetStartPosition() is an inline function, which causes it to exist in the application's code. This means that BEFORE_START_POSITION as returned by GetStartPosition() contains the application's DS.
On the other hand, GetNextAssoc() is not inline and exists in MFC200.DLL. Consider CMapStringToOb. On line 249 of MAP_SO.CPP is the comparison:
if (pAssocRet == (CAssoc*) BEFORE_START_POSITION)
This comparison is intended to succeed when pAssocRet is the value
returned by GetStartPosition(). However, BEFORE_START_POSITION in the
above line contains the DLL's DS, and thus the comparison fails, in
which case GetNextAssoc() proceeds to use pAssocRet, and a GP fault
results.
When building a debug version of the application, inlining is turned off and both GetStartPosition() and GetNextAssoc() exist in MFC200D.DLL. For a non-AFXDLL application, both functions are linked into the application's code (both debug and retail). The same DS is used in all of these cases and GetNextAssoc() works correctly.
Additional reference words: 1.00 2.00 CMapWordToOb CMapWordToPtr CMapPtrToWord CMapPtrToPtr CMapStringToPtr CMapStringToString KBCategory: kbprg kbfixlist kbbuglist KBSubcategory: MfcMisc
Keywords : kb16bitonly kbnokeyword kbMFC kbVC kbbuglist kbfixlist
Version : 1.00
Platform : WINDOWS
Solution Type : kbfix
Last Reviewed: September 19, 1997