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.