ID Number: Q51031
2.03 2.10 3.00
WINDOWS
Summary:
SYMPTOMS
Define a global variable above the WinMain() routine with code
similar to the following:
#include <windows.h>
LPSTR Str = "testing";
Then in the window procedure, use the TextOut() function to display
"Str". Garbage (strange characters) is displayed on the screen.
This problem only occurs in real mode.
If "Str" is defined in the same manner, this time as a local
variable, however, this problem does not occur.
CAUSE
This problem is a result of the way the string was declared. By
declaring "Str" as an LPSTR, it is statically declared as a far
pointer. The far pointer is resolved when the application is first
loaded. If DGROUP moves [which can happen when calling LocalAlloc()
when yielding control to other applications with Yield() or
GetMessage() or PeekMessage()], "Str" will become invalid. This
happens to work for the local variable because the pointer is
resolved when the function is entered, and the program is not
yielding in the function. Therefore, the pointer remains valid
throughout the life of the function call.
RESOLUTION
Pointers should be declared and used as follows:
1. Declare pointers to data in the data segment (DS) as NEAR. For
example:
char * Str = "testing";
2. Cast the pointer to FAR when making the following function call:
TextOut(hDC, x, y, (LPSTR) Str, nCount);
(Actually, if there is a prototype for the function, it is not
necessary to cast the argument, since the prototype will perform
an implicit cast.) The reason it works to dynamically cast a
NEAR pointer to a FAR is that the compiler generates code to
PUSH DS as the function call is being made. Even if the DS
changes from time to time (as it often does in Windows), the
code will always push the CURRENT value of DS on the stack when
calling a function.
3. Pointers should be declared as FAR only if they will be assigned
values dynamically. For example:
char * Str = "testing";
LPSTR lpStr;
...
lpStr = (LPSTR) Str;
TextOut(hDC, x, y, lpStr, nCount);