The STRPROG Program

The STRPROG program, shown in Figure 19-2, is fairly straightforward. The two menu options (Enter and Delete) invoke dialog boxes that allow you to enter a string. STRPROG then calls AddString or DeleteString. When the program needs to update its client area, it calls GetStrings and uses the function GetStrCallBack to list the enumerated strings.

STRPROG.MAK

#-----------------------

# STRPROG.MAK make file

#-----------------------

strprog.exe : strprog.obj strprog.res strprog.def

link strprog, /align:16, NUL, /nod slibcew libw, strprog

rc strprog.res

strprog.obj : strprog.c strprog.h

cl -c -Gsw -Ow -W2 -Zp strprog.c

strprog.res : strprog.rc strprog.h

rc -r strprog.rc

STRPROG.C

/*--------------------------------------------------------

STRPROG.C -- Program using STRLIB dynamic link library

(c) Charles Petzold, 1990

--------------------------------------------------------*/

#include <windows.h>

#include <string.h>

#include "strprog.h"#define MAXLEN 32

#define WM_DATACHANGE WM_USER

typedef struct

{

HDC hdc ;

short xText ;

short yText ;

short xStart ;

short yStart ;

short xIncr ;

short yIncr ;

short xMax ;

short yMax ;

}

CBPARM ;

BOOL FAR PASCAL AddString (LPSTR) ; // functions in STRLIB

BOOL FAR PASCAL DeleteString (LPSTR) ;

short FAR PASCAL GetStrings (FARPROC, CBPARM FAR *) ;

long FAR PASCAL WndProc (HWND, WORD, WORD, LONG) ;

char szAppName [] = "StrProg" ;

char szString [MAXLEN] ;

int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,

LPSTR lpszCmdLine, int nCmdShow)

{

HWND hwnd ;

MSG msg ;

WNDCLASS wndclass ;

if (!hPrevInstance)

{

wndclass.style = CS_HREDRAW | CS_VREDRAW ;

wndclass.lpfnWndProc = WndProc ;

wndclass.cbClsExtra = 0 ;

wndclass.cbWndExtra = 0 ;

wndclass.hInstance = hInstance ;

wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;

wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;

wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ;

wndclass.lpszMenuName = szAppName ;

wndclass.lpszClassName = szAppName ;

RegisterClass (&wndclass) ;

}

hwnd = CreateWindow (szAppName, "DLL Demonstration Program",

WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT,

CW_USEDEFAULT, CW_USEDEFAULT,

NULL, NULL, hInstance, NULL) ;

ShowWindow (hwnd, nCmdShow) ;

UpdateWindow (hwnd) ;

while (GetMessage (&msg, NULL, 0, 0))

{

TranslateMessage (&msg) ;

DispatchMessage (&msg) ;

}

return msg.wParam ;

}

BOOL FAR PASCAL DlgProc (HWND hDlg, WORD message, WORD wParam, LONG lParam)

{

switch (message)

{

case WM_INITDIALOG :

SendDlgItemMessage (hDlg, IDD_STRING, EM_LIMITTEXT,

MAXLEN - 1, 0L) ;

return TRUE ;

case WM_COMMAND :

switch (wParam)

{

case IDOK :

GetDlgItemText (hDlg, IDD_STRING, szString, MAXLEN) ;

EndDialog (hDlg, TRUE) ;

return TRUE ;

case IDCANCEL :

EndDialog (hDlg, FALSE) ;

return TRUE ;

}

}

return FALSE ;

}

BOOL FAR PASCAL EnumCallBack (HWND hwnd, LONG lParam)

{

char szClassName [16] ;

GetClassName (hwnd, szClassName, sizeof szClassName) ;

if (0 == strcmp (szClassName, szAppName))

SendMessage (hwnd, WM_DATACHANGE, 0, 0L) ;

return TRUE ;

}

BOOL FAR PASCAL GetStrCallBack (LPSTR lpString, CBPARM FAR *lpcbp)

{

TextOut (lpcbp->hdc, lpcbp->xText, lpcbp->yText,

lpString, lstrlen (lpString)) ;

if ((lpcbp->yText += lpcbp->yIncr) > lpcbp->yMax)

{

lpcbp->yText = lpcbp->yStart ;

if ((lpcbp->xText += lpcbp->xIncr) > lpcbp->xMax)

return FALSE ;

}

return TRUE ;

}

long FAR PASCAL WndProc (HWND hwnd, WORD message, WORD wParam, LONG lParam)

{

static FARPROC lpfnDlgProc, lpfnGetStrCallBack, lpfnEnumCallBack ;

static HANDLE hInst ;

static short cxChar, cyChar, cxClient, cyClient ;

CBPARM cbparam ;

HDC hdc ;

PAINTSTRUCT ps ;

TEXTMETRIC tm ;

switch (message)

{

case WM_CREATE :

hInst = ((LPCREATESTRUCT) lParam)->hInstance ;

lpfnDlgProc = MakeProcInstance (DlgProc, hInst) ;

lpfnGetStrCallBack = MakeProcInstance (GetStrCallBack, hInst) ;

lpfnEnumCallBack = MakeProcInstance (EnumCallBack, hInst) ;

hdc = GetDC (hwnd) ;

GetTextMetrics (hdc, &tm) ;

cxChar = tm.tmAveCharWidth ;

cyChar = tm.tmHeight + tm.tmExternalLeading ;

ReleaseDC (hwnd, hdc) ;

return 0 ;

case WM_COMMAND :

switch (wParam)

{

case IDM_ENTER :

if (DialogBox (hInst, "EnterDlg", hwnd, lpfnDlgProc))

{

if (AddString (szString))

EnumWindows (lpfnEnumCallBack, 0L) ;

else

MessageBeep (0) ;

}

break ;

case IDM_DELETE :

if (DialogBox (hInst, "DeleteDlg", hwnd, lpfnDlgProc))

{

if (DeleteString (szString))

EnumWindows (lpfnEnumCallBack, 0L) ;

else

MessageBeep (0) ;

}

break ;

}

return 0 ;

case WM_SIZE :

cxClient = LOWORD (lParam) ;

cyClient = HIWORD (lParam) ;

return 0 ;

case WM_DATACHANGE :

InvalidateRect (hwnd, NULL, TRUE) ;

return 0 ;

case WM_PAINT :

hdc = BeginPaint (hwnd, &ps) ;

cbparam.hdc = hdc ;

cbparam.xText = cbparam.xStart = cxChar ;

cbparam.yText = cbparam.yStart = cyChar ;

cbparam.xIncr = cxChar * MAXLEN ;

cbparam.yIncr = cyChar ;

cbparam.xMax = cbparam.xIncr * (1 + cxClient / cbparam.xIncr) ;

cbparam.yMax = cyChar * (cyClient / cyChar - 1) ;

GetStrings (lpfnGetStrCallBack, &cbparam) ;

EndPaint (hwnd, &ps) ;

return 0 ;

case WM_DESTROY :

PostQuitMessage (0) ;

return 0 ;

}

return DefWindowProc (hwnd, message, wParam, lParam) ;

}

STRPROG.RC

/*----------------------------

STRPROG.RC resource script

----------------------------*/

#include <windows.h>

#include "strprog.h"

StrProg MENU

{

MENUITEM "&Enter!", IDM_ENTER

MENUITEM "&Delete!", IDM_DELETE

}

EnterDlg DIALOG 24, 24, 190, 44

STYLE WS_POPUP | WS_DLGFRAME

{

LTEXT "&Enter:", 0, 4, 8, 24, 8

EDITTEXT IDD_STRING, 32, 6, 154, 12

DEFPUSHBUTTON "Ok", IDOK, 44, 24, 32, 14

PUSHBUTTON "Cancel", IDCANCEL, 114, 24, 32, 14

}

DeleteDlg DIALOG 24, 24, 190, 44

STYLE WS_POPUP | WS_DLGFRAME

{

LTEXT "&Delete:", 0, 4, 8, 28, 8

EDITTEXT IDD_STRING, 36, 6, 150, 12

DEFPUSHBUTTON "Ok", IDOK, 44, 24, 32, 14

PUSHBUTTON "Cancel", IDCANCEL, 114, 24, 32, 14

}

STRPROG.H

/*-----------------------

STRPROG.H header file

-----------------------*/

#define IDM_ENTER 1

#define IDM_DELETE 2

#define IDD_STRING 0x10

STRPROG.DEF

;------------------------------------

; STRPROG.DEF module definition file

;------------------------------------

NAME STRPROG

DESCRIPTION 'Program using STRLIB DLL (c) Charles Petzold, 1990'

EXETYPE WINDOWS

STUB 'WINSTUB.EXE'

CODE PRELOAD MOVEABLE DISCARDABLE

DATA PRELOAD MOVEABLE MULTIPLE

HEAPSIZE 1024

STACKSIZE 8192

EXPORTS WndProc

DlgProc

GetStrCallBack

EnumCallBack

IMPORTS STRLIB.AddString

STRLIB.DeleteString

STRLIB.GetStrings

Near the top of the STRPROG.C source code file are declarations of the three functions in STRLIB that STRPROG will call:

BOOL FAR PASCAL AddString (LPSTR) ;

BOOL FAR PASCAL DeleteString (LPSTR) ;

short FAR PASCAL GetStrings (FARPROC, CBPARM FAR *) ;

If you plan to use library functions in several different programs, you'll want to put the declarations in a header file. This header file will be similar to (although I hope not as long as) WINDOWS.H.

These three functions are also listed in the IMPORTS section of STRPROG's module definition file:

IMPORTS STRLIB.AddString

STRLIB.DeleteString

STRLIB.GetStrings

These correspond to the three functions in the EXPORTS section of STRLIB.DEF. The IMPORTS section directs LINK to add information to STRPROG.EXE that allows Win- dows to dynamically link STRPROG's calls to these functions with the actual function routines in STRLIB.DLL. The EXPORTS section in STRLIB.DEF makes the functions in STRLIB.DLL available to other modules. The IMPORTS section in STRPROG.DEF indicates the module—STRLIB—and the functions in STRLIB that STRPROG requires.