The Use of Call-Back Functions

Now that we know what these function prologs look like, let's examine what happens when STRPROG calls the GetStrings function. GetStrings requires a call-back function in STRPROG called GetStrCallBack.

Because GetStrCallBack is exported, Windows inserts NOPs in the first 2 bytes of the function when STRPROG's code segment is loaded into memory. While processing the WM_CREATE message, STRPROG calls MakeProcInstance for this function:

lpfnGetStrCallBack = MakeProcInstance (GetStrCallBack, hInst) ;

On return from MakeProcInstance, the variable lpfnGetStrCallBack points to code that looks like this:

MOV AX, yyyy

JMP GetStrCallBack

where yyyy is the data segment address of this instance of STRPROG.

STRPROG calls GetStrings to update its client area:

GetStrings (lpfnGetStrCallBack, &cbparam) ;

The GetStrings function is in STRLIB. The parameter cbparam is a structure containing information that GetStrings simply passes back to GetStrCallBack, which then uses the information to display the strings in the client area.

In STRLIB, the prolog to GetStrings sets AX equal to the data segment of the library, saves the current value of DS (the data segment of STRPROG), and sets DS equal to AX. Now the function can use its own data segment to obtain the strings currently stored. When it obtains a string, it calls the call-back function passed as a parameter to GetStrings:

bReturn = (*lpfnGetStrCallBack) ((LPSTR) npString, lpParam) ;

This actually calls the instance thunk for GetStrCallBack set up by MakeProcInstance. The instance thunk sets AX equal to STRPROG's data segment. The function prolog saves the current value of DS (the data segment of STRLIB) and sets DS equal to AX. Now GetStrCallBack is using STRPROG's own data segment and can process the string. When GetStrCallBack returns control to GetStrings, the function epilog restores the original value of DS, which is STRLIB's data segment. GetStrings is ready to find the next string.

When GetStrings is finished, the function epilog restores the value of DS to STRPROG's data segment. As you can see, although control bounces back and forth between STRPROG and STRLIB, each module is always using its own data segment. During this entire process, however, the stack segment never changes. It is always STRPROG's stack segment. For code in STRPROG, this situation is just fine. For code in STRLIB, it can pose some problems.