PRB: Global Variable Is Not Displayed Correctly by TextOut()

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);