home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
drdobbs
/
1989
/
03
/
johnson.lst
< prev
next >
Wrap
File List
|
1989-02-10
|
48KB
|
1,360 lines
_DYNAMIC LINK LIBRARIES UNDER MICROSOFT WINDOWS_
by Margaret Johnson and Mark Solinski
[LISTING ONE]
/****************************************************************************
* MODULE: HELPLIB.C
* COMMENTS: contains the functions Screen and Topics (see HELPDLG.C)
****************************************************************************/
#include <windows.h> /* used by all modules written for Windows */
#include "helplib.h" /* library's include file */
#define HELPLIB
#include "prothelp.h" /* function prototypes */
/****************************************************************************
* external variables
****************************************************************************/
extern HANDLE hInst; /* set by the initialization function in libinitc.c */
/****************************************************************************
* global variables
****************************************************************************/
LPSCREEN lpsc;
BOOL TOPICS;
BOOL SCR;
/****************************************************************************
* Local variables
****************************************************************************/
static FARPROC lpfnScreenDlgProc;
static FARPROC lpfnTopicsDlgProc;
/************************************************************************
* FUNCTION: Screen
* PURPOSE: Display help text on a topic.
************************************************************************/
BOOL FAR PASCAL Screen( LPSCREEN sc )
{MSG msg;
HWND hWnd;
LockData(0);
lpsc = sc;
if (!(lpfnScreenDlgProc = MakeProcInstance(ScreenDlgProc,hInst)))
return FALSE;
if (!(hWnd = CreateDialog(hInst,"HELP_BOX",GetActiveWindow(),
lpfnScreenDlgProc)))
return FALSE;
while (GetMessage (&msg,NULL,0,0))
{if (!IsDialogMessage(hWnd,&msg) )
{TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
FreeProcInstance(lpfnScreenDlgProc);
if (TOPICS)
{Topics(lpsc);
}
UnlockData(0);
return TRUE;
}
/************************************************************************
* FUNCTION: Topics
* PURPOSE: to present a listbox of currently available help topics.
************************************************************************/
VOID FAR PASCAL Topics( LPSCREEN sc )
{LockData(0);
lpsc = sc;
lpfnTopicsDlgProc = MakeProcInstance(TopicsDlgProc,hInst);
DialogBox(hInst,"TOPICS_BOX",GetActiveWindow(),lpfnTopicsDlgProc);
FreeProcInstance(lpfnTopicsDlgProc);
if (SCR)
{Screen(lpsc);
}
UnlockData(0);
return;
}
[LISTING TWO]
/****************************************************************************
* FILE: helplib.rc
* PURPOSE:resource file for the helplib DLL
***************************************************************************/
#include <style.h>
#include "helplib.h"
#define TABGRP (WS_TABSTOP | WS_GROUP)
VSRUNTIME TEXT vsruntime.asc
CAVEATS TEXT caveats.asc
COOKBOOK TEXT cookbook.asc
REF TEXT ref.asc
A TEXT a.asc
B TEXT b.asc
C TEXT c.asc
STRINGTABLE
BEGIN
IDS_MEMERROR "Out of Memory"
VSRUNTIME, "versus run time libraries"
CAVEATS, "caveats"
COOKBOOK, "cookbook"
REF, "references"
A, "a"
B, "b"
C, "c"
END
rcinclude HELP.dlg
rcinclude TOPICS.dlg
[LISTING THREE]
/***************************************************************************
* FILE: helplib.h
* PURPOSE: include file for the helplib DLL
**************************************************************************/
typedef struct {
WORD wScreen;
WORD wStart;
WORD wEnd;
}SCREEN, FAR * LPSCREEN, NEAR *NPSCREEN;
#define ID_SCREEN_HELP 100
#define ID_LB_TOPICS 101
#define ID_NEXT_HELP 102
#define ID_PREVIOUS_HELP 103
#define ID_TOPICS_HELP 104
#define ID_SCROLL_HELP 105
#define VSRUNTIME 300
#define CAVEATS 301
#define COOKBOOK 302
#define REF 303
#define A 500
#define B 501
#define C 502
#define IDS_MEMERROR 1000
[LISTING FOUR]
/**************************************************************************
* MODULE: HELPDLG.C
**************************************************************************/
#include <windows.h> /* required for all Windows applications */
#include "helplib.h" /* library's include file */
#define HELPLIB
#include "prothelp.h" /* function prototypes */
#include "string.h" /* strlen */
/*************************************************************************
* to allow multiple screens from different apps/instances
*************************************************************************/
typedef struct screenStruct {
WORD wScreen;
WORD wStart;
WORD wEnd;
int nPage;
int nTopics;
int nNumLines;
HWND hScroll;
int nVscrollPos;
}HELPSCREEN, *NPHELPSCREEN;
/****************************************************************************
* local variables
****************************************************************************/
#define GWW_SCREENHANDLE 0
#define MAXBUFLEN 80
#define MAXLINES 250
#define LOCAL static
/*************************************
* scroll bar positioning variables
*************************************/
LOCAL int nVscrollMax;
/*************************************
* buffer to hold the help text
*************************************/
LOCAL char szText[MAXLINES][MAXBUFLEN];
/*******************************************
* screen information
*******************************************/
LOCAL NPHELPSCREEN sptr;
/****************************************************************************
* local function prototypes
****************************************************************************/
LOCAL VOID NEAR getText ( VOID );
LOCAL VOID NEAR setScroll ( VOID );
LOCAL VOID NEAR setNewHelp ( HWND );
LOCAL HANDLE NEAR setToScreen ( HWND );
LOCAL BOOL NEAR differentScreen ( HWND );
LOCAL BOOL NEAR initScreen ( HWND );
LOCAL VOID NEAR freeScreen ( HANDLE );
/****************************************************************************
* external variables
****************************************************************************/
extern HANDLE hInst; /* set by the initialization function in libinitc.c */
extern LPSCREEN lpsc; /* passed in by the calling function */
extern BOOL TOPICS;/* used by ScreenDlgProc when the user requests Topics */
extern BOOL SCR; /* used by TopicsDlgProc when the use requests Help */
/****************************************************************************
* Function: ScreenDlgProc
* Purpose: To respond to the Push Buttons: Topics, Next, Previous, and
* Cancel on the Screen() dialog box.
****************************************************************************/
BOOL FAR PASCAL ScreenDlgProc(HWND hDlg, WORD wMessage, WORD wParam,
LONG lParam)
{int i;
static BOOL bImoved=FALSE;
HWND hWndScreen;
HANDLE hScreen;
switch(wMessage)
{
case WM_INITDIALOG:
hScreen = setToScreen(hDlg);
sptr->nTopics = sptr->wEnd - sptr->wStart + 1;
sptr->hScroll = GetDlgItem(hDlg,ID_SCROLL_HELP);
getText();
LocalUnlock(hScreen);
break;
case WM_MOVE:
bImoved=TRUE;
break;
case WM_VSCROLL:
if (bImoved)
{hScreen = setToScreen(hDlg);
getText();
setScroll();
LocalUnlock(hScreen);
bImoved=FALSE;
}
hWndScreen = GetWindow(hDlg,GW_CHILD);
SendMessage(hWndScreen,WM_VSCROLL,wParam,lParam);
break;
case WM_COMMAND:
hScreen = setToScreen(hDlg);
hWndScreen = GetWindow(hDlg,GW_CHILD);
switch(wParam)
{
case ID_PREVIOUS_HELP:
sptr->wScreen = sptr->wStart + (sptr->wScreen-sptr->wStart+
(sptr->nTopics-1)) % sptr->nTopics;
setNewHelp(hWndScreen);
LocalUnlock(hScreen);
break;
case ID_NEXT_HELP:
sptr->wScreen = sptr->wStart + (sptr->wScreen-sptr->wStart+1)
%sptr->nTopics;
setNewHelp(hWndScreen);
LocalUnlock(hScreen);
break;
case ID_TOPICS_HELP:
TOPICS = TRUE;
case IDCANCEL:
freeScreen(hScreen);
DestroyWindow(hDlg);
break;
default:
return FALSE;
}
break;
case WM_ACTIVATE: /* when the dialog is activated, check to
* see if the correct screen mode is
* is selected.
*/
if (!wParam)
break;
case WM_PAINT: /* User could be switching 'tween n application's
* (or n instances) Help Dialogs
*/
hScreen = setToScreen(hDlg);
if (differentScreen(hDlg))
{getText();
}
if (WM_ACTIVATE == wMessage)
{SetFocus(sptr->hScroll);
setScroll();
}
LocalUnlock(hScreen);
return FALSE;
default:
return FALSE;
}
return TRUE;
}
/****************************************************************************
* Function: ScreenWndProc
* Purpose: To respond to messages received by the Screen() window.
* Notes: The WM_VSCROLL, WM_PAINT message handling was derived from
* Programming Windows by Charles Petzold, pp. 117-122.
****************************************************************************/
long FAR PASCAL ScreenWndProc(HWND hWnd, WORD wMessage, WORD wParam,
LONG lParam)
{PAINTSTRUCT ps;
LOCAL int xChar,yChar;
LOCAL int yClient;
LOCAL TEXTMETRIC tm;
int i;
int nVscrollInc;
int nPaintBeg,nPaintEnd;
HDC hDC;
HANDLE hScreen;
switch(wMessage)
{
case WM_CREATE:
if (!initScreen(hWnd))
break;
hDC = GetDC(hWnd);
GetTextMetrics(hDC,&tm);
ReleaseDC(hWnd,hDC);
xChar = tm.tmAveCharWidth;
yChar = tm.tmHeight + tm.tmExternalLeading;
TOPICS = FALSE;
break;
case WM_SIZE:
hScreen = GetWindowWord(hWnd,GWW_SCREENHANDLE);
sptr = (NPHELPSCREEN)LocalLock(hScreen);
yClient = HIWORD(lParam);
sptr->nPage = yClient / yChar ;
LocalUnlock(hScreen);
break;
case WM_SETFOCUS:
hScreen = GetWindowWord(hWnd, GWW_SCREENHANDLE);
sptr = (NPHELPSCREEN)LocalLock(hScreen);
SetFocus(sptr->hScroll);
LocalUnlock(hScreen);
break;
/* the WM_VSCROLL message is sent by the ScreenDlgProc, which has
* already taken care of sptr
*/
case WM_VSCROLL:
switch (wParam)
{
case SB_TOP:
nVscrollInc = -sptr->nVscrollPos;
break;
case SB_BOTTOM:
nVscrollInc = nVscrollMax - sptr->nVscrollPos;
break;
case SB_LINEUP:
nVscrollInc = -1;
break;
case SB_LINEDOWN:
nVscrollInc = 1;
break;
case SB_PAGEUP:
nVscrollInc = min(-1, -sptr->nPage) ;
break;
case SB_PAGEDOWN:
nVscrollInc = max(1, sptr->nPage) ;
break;
case SB_THUMBPOSITION:
nVscrollInc = LOWORD(lParam) - sptr->nVscrollPos;
break;
default:
nVscrollInc = 0;
}
if (nVscrollInc = max(-sptr->nVscrollPos,
min(nVscrollInc, nVscrollMax - sptr->nVscrollPos)))
{sptr->nVscrollPos += nVscrollInc;
ScrollWindow(hWnd, 0, -yChar * nVscrollInc, NULL, NULL);
UpdateWindow(hWnd);
SetScrollPos(sptr->hScroll,SB_CTL,sptr->nVscrollPos,TRUE);
}
break;
case WM_PAINT:
hScreen = GetWindowWord(hWnd, GWW_SCREENHANDLE);
sptr = (NPHELPSCREEN)LocalLock(hScreen);
BeginPaint( hWnd, &ps );
nPaintBeg = max(0,sptr->nVscrollPos + ps.rcPaint.top/yChar - 1);
nPaintEnd = min(sptr->nNumLines,
sptr->nVscrollPos + ps.rcPaint.bottom / yChar);
for (i=nPaintBeg; i < nPaintEnd; ++i)
{TextOut(ps.hdc,xChar,yChar * (1 - sptr->nVscrollPos+i),
szText[i],strlen(szText[i]));
}
EndPaint(hWnd,&ps);
LocalUnlock(hScreen);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc( hWnd, wMessage, wParam, lParam );
}
return 0L;
}
/****************************************************************************
* Function: TopicsDlgProc
* Purpose: To respond to the list box and push button messages
* of the Topics() dialog box.
****************************************************************************/
BOOL FAR PASCAL TopicsDlgProc(HWND hDlg, WORD wMessage, WORD wParam,
LONG lParam)
{int i;
LOCAL char szBuff[MAXBUFLEN];
switch(wMessage)
{
case WM_INITDIALOG:
SetSysModalWindow(hDlg);
for (i=lpsc->wStart;i<=lpsc->wEnd;++i)
{LoadString(hInst,i,szBuff,MAXBUFLEN);
SendDlgItemMessage(hDlg,ID_LB_TOPICS,LB_ADDSTRING,0,
(LONG)(LPSTR)szBuff);
}
SendDlgItemMessage(hDlg,ID_LB_TOPICS,LB_SETCURSEL,0,0L);
SCR = FALSE;
break;
case WM_COMMAND:
switch(wParam)
{
case ID_LB_TOPICS:
if ((HIWORD(lParam)) != LBN_DBLCLK)
{break;
}
case IDOK:
lpsc->wScreen = (WORD)SendDlgItemMessage(hDlg,ID_LB_TOPICS,
LB_GETCURSEL,0,0L) + lpsc->wStart;
SCR=TRUE;
case IDCANCEL:
EndDialog(hDlg,TRUE);
break;
default:
return FALSE;
}
break;
default:
return FALSE;
}
return TRUE;
}
/****************************************************************************
* Function: getText
* Purpose: To retrieve the help text for the current screen from the
* Help library's resource file.
****************************************************************************/
LOCAL VOID NEAR getText( )
{LPSTR lpText,lpTextBeg;
HANDLE hRes;
hRes = LoadResource(hInst,
FindResource(hInst,MAKEINTRESOURCE(sptr->wScreen),"TEXT"));
lpText = LockResource(hRes);
sptr->nNumLines=0;
lpTextBeg = lpText;
while (*lpText != '\0' && *lpText != '\x1A' )
{if (*lpText == '\r')
{*lpText = '\0';
lstrcpy(szText[sptr->nNumLines++],lpTextBeg);
if (sptr->nNumLines >= MAXLINES)
break;
*lpText='\r';
lpText = AnsiNext(lpText);
if (*lpText = '\l')
lpText = AnsiNext(lpText);
lpTextBeg = lpText;
}
else
lpText = AnsiNext(lpText);
}
*lpText = '\0';
lstrcpy(szText[sptr->nNumLines++],lpTextBeg);
GlobalUnlock(hRes);
FreeResource(hRes);
}
/****************************************************************************
* Function: setScroll
* Purpose: To set the scroll bar control's range and initial position.
****************************************************************************/
LOCAL VOID NEAR setScroll( )
{nVscrollMax = max(0, sptr->nNumLines + 2 - sptr->nPage);
SetScrollRange(sptr->hScroll, SB_CTL,0, nVscrollMax, FALSE);
SetScrollPos (sptr->hScroll, SB_CTL,sptr->nVscrollPos,TRUE);
}
/****************************************************************************
* Function: setNewHelp
* Purpose: Get the right screen help info
****************************************************************************/
LOCAL VOID NEAR setNewHelp(HWND hWnd)
{sptr->nVscrollPos = 0;
getText();
setScroll();
InvalidateRect(hWnd,NULL,TRUE);
SetFocus(sptr->hScroll);
}
/****************************************************************************
* Function: setToScreen
* Purpose: Lock the screen pointer to the correct screen info.
****************************************************************************/
LOCAL HANDLE NEAR setToScreen(HWND hWnd )
{HANDLE hScreen;
HWND hWndScreen;
hWndScreen = GetWindow(hWnd,GW_CHILD);
hScreen = GetWindowWord(hWndScreen, GWW_SCREENHANDLE);
sptr = (NPHELPSCREEN)LocalLock( hScreen );
return hScreen;
}
/****************************************************************************
* Function: differentScreen
* Purpose: Find out if hDlg references the same window as the last call
****************************************************************************/
LOCAL BOOL NEAR differentScreen(HWND hDlg)
{LOCAL HWND hWnd = NULL;
if (hWnd != hDlg)
{hWnd = hDlg;
return TRUE;
}
return FALSE;
}
/****************************************************************************
* Function: initScreen
* Purpose: Set up the screen on a WM_CREATE message.
****************************************************************************/
LOCAL BOOL NEAR initScreen(HWND hWnd)
{HANDLE hScreen;
char szMemErr[15];
if (!(hScreen = LocalAlloc(LHND,sizeof(HELPSCREEN))))
{LoadString(hInst,IDS_MEMERROR,szMemErr,15);
MessageBox( GetParent(hWnd), szMemErr, NULL, MB_ICONEXCLAMATION);
return FALSE;
}
sptr = (NPHELPSCREEN)LocalLock(hScreen);
sptr->wScreen = lpsc->wScreen;
sptr->wStart = lpsc->wStart;
sptr->wEnd = lpsc->wEnd;
LocalUnlock(hScreen);
SetWindowWord( hWnd, GWW_SCREENHANDLE, hScreen );
return TRUE;
}
/****************************************************************************
* Function: freeScreen
* Purpose: All done with the screen, so release the memory.
****************************************************************************/
LOCAL VOID NEAR freeScreen(HANDLE hScreen)
{lpsc->wScreen = sptr->wScreen;
lpsc->wEnd = sptr->wEnd;
lpsc->wStart = sptr->wStart;
LocalUnlock(hScreen);
LocalFree(hScreen);
}
[LISTING FIVE]
/*
* Utilities library C language initialization.
*/
#include <windows.h>
#include "helplib.h"
#include "prothelp.h"
/**********************************************************************
* function prototypes
**********************************************************************/
#define LOCAL static
int NEAR PASCAL LibInitC ( HANDLE );
LOCAL BOOL NEAR registerWindow ( VOID );
/**********************************************************************
* Global vars
**********************************************************************/
HANDLE hInst;
/**********************************************************************
* C init called from the asm entry point init.
* We require that the library have exactly one DS. See libinita.asm.
* The DS can (should) be moveable.
***********************************************************************/
int NEAR PASCAL LibInitC(HANDLE hInstance)
{
hInst = hInstance;
return(registerWindow());
}
/************************************************************************/
LOCAL BOOL NEAR registerWindow ( )
{WNDCLASS WndClass; /* Window class structure */
WndClass.style = CS_HREDRAW | CS_VREDRAW;
WndClass.lpfnWndProc = ScreenWndProc;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = sizeof(HANDLE);
WndClass.hInstance = hInst;
WndClass.hIcon = NULL;
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hbrBackground = COLOR_WINDOW+1;
WndClass.lpszMenuName = NULL;
WndClass.lpszClassName = "Screen";
return RegisterClass(&WndClass);
}
[LISTING SIX]
; LIBINITA.ASM - - - Define entry point and perform initialization
; for libraries that have their own data segments.
TITLE LIBINITA
?PLM = 1
?WIN = 1
memM = 1
.xlist
include cmacros.inc
.list
externFP <LocalInit>
externFP <UnlockSegment>
externNP <LibInitC>
;
; cx = size of the heap as defined in the .def file.
; di = "Instance handle". This is the C hInstance passed to WinMain.
; NOTE: For a WINDOWS library, hModule is interchangeable with
; hInstance.
; This is a handle to the global object containing the DS if there
; is one. If there is no DS for a library, it is the module handle,
; which is also a pointer to the module since that's a fixed global
; object.
; NOTE: The meaning and contents of hInstance are undocumented and
; should not be relied upon. That is, you may asuume that the value
; in di may be passed to any routine expecting hInstance. Making
; any other assumptions is VERY dangerous since the contents of
; hInstance may change in future versions.
; ds = data segment for our heap.
; es:si = pointer to the command line.
_INIT SEGMENT BYTE PUBLIC 'CODE'
assume CS: _INIT ; ???? assume vs assumes? ???????????????????
assumes DS,NOTHING ; ???? assume vs assumes? ???????????????????
assumes ES,NOTHING ; ???? assume vs assumes? ???????????????????
cProc LibInitA, <FAR, PUBLIC, NODATA>, <si,di>
cBegin
xor ax,ax ; Return failure if there is no heap.
jcxz ourexit
cCall LocalInit,<ds,ax,cx> ; Set up our DS for doing LocalAllocs.
or ax,ax
jz ourexit
cCall LibInitC,<di> ; Do any C initialization.
; di = hInstance.
push ax ; Save the return value.
mov ax,-1
cCall UnlockSegment,<ax> ; NOTE that we leave DS unlocked.
; This implies that we must use
; Lock/UnlockData as we enter and
; any routines which access our
; data segment.
pop bx
or ax,ax ; Check if either one failed.
jz ourexit
or bx,bx
jnz ourexit
xor ax,ax
ourexit:
cEnd
_INIT ENDS
end LibInitA
[LISTING SEVEN]
LIBRARY helplib
DESCRIPTION 'Copyright 1988, mkj'
STUB 'WINSTUB.EXE'
CODE LOADONCALL MOVEABLE DISCARDABLE
DATA MOVEABLE SINGLE
HEAPSIZE 2048
CODE MOVEABLE
SEGMENTS _INIT PRELOAD MOVEABLE DISCARDABLE
HELPLIB MOVEABLE LOADONCALL DISCARDABLE
EXPORTS
Screen @1
Topics @2
ScreenDlgProc @3
ScreenWndProc @4
TopicsDlgProc @5
[LISTING EIGHT]
#
# FILE: helplib
# PURPOSE: make file for the helplib DLL
#
COMP = -c -Alnw -Gsw -Zp -Os -FPa -W2 -D LINT_ARGS
OBJS = helplib.obj helpdlg.obj libinita.obj libinitc.obj helplib.res
LOBJS = helplib+helpdlg+libinita+libinitc
.rc.res:
rc -r $*.rc
.asm.obj:
masm $*;
helplib.res: helplib.rc helplib.h vsruntim.asc caveats.asc \
cookbook.asc ref.asc help.dlg topics.dlg
helplib.obj: helplib.c helplib.h prothelp.h
cl $(COMP) -NT $* $*.c
helpdlg.obj: helpdlg.c helplib.h prothelp.h
cl $(COMP) -NT HELPLIB $*.c
libinita.obj: libinita.asm
masm $*;
libinitc.obj: libinitc.c
cl $(COMP) -NT _INIT $*.c
helplib.exe: $(OBJS) helplib.def
link4 $(LOBJS),helplib.exe/align:16,/map/li,mwinlibc mlibw mlibca /NOE ,helplib.def
rc helplib.res helplib.exe
implib helplib.lib helplib.def
[LISTING NINE]
/**********************************************************************
* FILE: helpdemo.c
* PURPOSE: to demonstrate the use of the helplib DLL
**********************************************************************/
#include <windows.h>
#include "helpdemo.h"
HANDLE hInstance; /* The Instance handle */
char szClass[10]; /* Window class name (see the .rc file) */
char szTitle[40]; /* Window title (see the .rc file) */
char szAbout[40]; /* About box string (see the .rc file */
static HWND hWnd;
long FAR PASCAL WndProc (HWND, unsigned, WORD, LONG);
BOOL NEAR Initialize( HANDLE, int );
/***********************************************************************
*Application main program.
***********************************************************************/
int PASCAL WinMain( hInst, hPrevInst, lpszCmdLine, nCmdShow )
HANDLE hInst; /* Our instance handle */
HANDLE hPrevInst; /* Previous instance of this application */
LPSTR lpszCmdLine; /* Pointer to any command line params */
int nCmdShow; /* Parameter to use for first ShowWindow */
{
MSG msg; /* Message structure */
HANDLE hAccel; /* Accelerator handle */
/* Save our instance handle in a global variable */
hInstance = hInst;
/* Initialize application, quit if any errors */
if( ! Initialize( hPrevInst, nCmdShow ) )
{return FALSE;
}
/* Main message processing loop. Get each message, then translate
* keyboard messages and finally dispatch each message to its window
* function.
*/
hAccel = LoadAccelerators(hInstance,szClass);
while( GetMessage( &msg, NULL, 0, 0 ) )
{if (!TranslateAccelerator(hWnd, hAccel, &msg))
{TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
return msg.wParam;
}
/************************************************************************
*Initialize the application.
*************************************************************************/
BOOL NEAR Initialize( hPrevInst, nCmdShow )
HANDLE hPrevInst; /* Previous instance handle, 0 if first */
int nCmdShow; /* Parameter from WinMain for ShowWindow */
{
WNDCLASS WndClass; /* Class structure for RegisterClass */
HMENU hMenu; /* Handle to the (system) menu */
if( ! hPrevInst ) {
/* Initialization for first instance only */
/* Load strings from resource file */
LoadString( hInstance, IDS_CLASS, szClass, sizeof(szClass) );
LoadString( hInstance, IDS_TITLE, szTitle, sizeof(szTitle) );
/* Register our window class */
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 = COLOR_WINDOW + 1;
WndClass.lpszMenuName = szClass;
WndClass.lpszClassName = szClass;
if( ! RegisterClass( &WndClass ) )
return FALSE;
}
else
{/* Initialization for subsequent instances only */
/* Copy data from previous instance */
GetInstanceData( hPrevInst, szClass, sizeof(szClass) );
GetInstanceData( hPrevInst, szTitle, sizeof(szTitle) );
}
/* Initialization for every instance */
/* Create the window */
hWnd = CreateWindow(
szClass, /* Class name */
szTitle, /* Window title */
WS_OVERLAPPEDWINDOW , /* window style */
CW_USEDEFAULT, /* x */
0, /* y */
CW_USEDEFAULT, /* x width */
0, /* y width */
NULL, /* Parent hWnd (none for top-level) */
NULL, /* Menu handle */
hInstance, /* Owning instance handle */
NULL /* Parameter to pass in WM_CREATE (none) */
);
/* Insert "About..." into system menu */
LoadString( hInstance, IDS_ABOUT, szAbout, sizeof(szAbout) );
hMenu = GetSystemMenu(hWnd, FALSE);
ChangeMenu(hMenu, 0, NULL, 999, MF_APPEND | MF_SEPARATOR);
ChangeMenu(hMenu, 0, (LPSTR)szAbout, IDS_ABOUT, MF_APPEND | MF_STRING);
/* Make the window visible */
ShowWindow( hWnd, nCmdShow );
/* Got all the information, update our display */
UpdateWindow( hWnd );
return TRUE;
}
[LISTING TEN]
/***************************************************************************
* FILE: wndproc.c
* PURPOSE: The functions WndProc and About for the helplib DLL demo.
***************************************************************************/
#include "windows.h"
#include "helpdemo.h"
extern HANDLE hInstance;
/******************* Message function prototypes *******************/
extern VOID HelpDemoMsg ( HWND, WORD, LONG );
/******************* local function prototype **********************/
BOOL NEAR paint ( HWND );
long FAR PASCAL WndProc( HWND, unsigned, WORD, LONG );
BOOL FAR PASCAL AboutDlgProc( HWND, unsigned, WORD, LONG );
long FAR PASCAL WndProc( hWnd, message, wParam, lParam )
HWND hWnd;
unsigned message;
WORD wParam;
LONG lParam;
{
FARPROC lpprocAbout;
switch (message)
{
case WM_SYSCOMMAND:
switch (wParam)
{
case IDS_ABOUT:
/* Bind callback function with module instance */
lpprocAbout = MakeProcInstance( (FARPROC)AboutDlgProc,
hInstance);
DialogBox( hInstance, MAKEINTRESOURCE(ABOUTBOX), hWnd,
lpprocAbout );
FreeProcInstance( (FARPROC)AboutDlgProc );
break;
default:
return DefWindowProc( hWnd, message, wParam, lParam );
}
break;
case WM_COMMAND:
switch(wParam)
{
case IDM_HELP:
HelpDemoMsg (hWnd, wParam, lParam);
break;
}
case WM_PAINT:
paint( hWnd );
break;
case WM_DESTROY:
case WM_CLOSE:
PostQuitMessage( 0 );
break;
default:
return DefWindowProc( hWnd, message, wParam, lParam );
break;
}
return(0L);
}
/*************************************************************************
* Paint procedure (for processing of WM_PAINT messages)
**************************************************************************/
BOOL NEAR paint ( hWnd )
HWND hWnd;
{
PAINTSTRUCT ps;
BeginPaint(hWnd,&ps);
EndPaint(hWnd,&ps);
return TRUE;
}
/**************************************************************************
* About Box
**************************************************************************/
BOOL FAR PASCAL AboutDlgProc( hDlg, message, wParam, lParam )
HWND hDlg;
unsigned message;
WORD wParam;
LONG lParam;
{
if (message == WM_COMMAND)
{EndDialog( hDlg, TRUE );
return TRUE;
}
else if (message == WM_INITDIALOG)
return TRUE;
else return FALSE;
}
[LISTING ELEVEN]
/***************************************************************************
* The message functions.
***************************************************************************/
#include "windows.h"
#include "helpdemo.h"
#include "helplib.h" /* library's help file */
#include "prothelp.h" /* prototypes for library's functions */
extern HANDLE hInstance;
/******************* local function prototypes *******************/
VOID HelpDemoMsg ( HWND, WORD, LONG );
/**************************************************************************/
VOID HelpDemoMsg( hWnd, wParam, lParam )
HWND hWnd;
WORD wParam;
LONG lParam;
{SCREEN sc;
sc.wStart = VSRUNTIME;
sc.wEnd = REF;
Topics(&sc);
}
[LISTING TWELVE]
/**************************************************************************
* FILE: prothelp.h
* PURPOSE:function prototypes for the helplib DLL
*************************************************************************/
#ifndef HELPDLG
#define HELPDLG extern
#endif
#ifndef HELPLIB
#define HELPLIB extern
#endif
HELPLIB BOOL FAR PASCAL Screen ( LPSCREEN );
HELPLIB VOID FAR PASCAL Topics ( LPSCREEN );
HELPDLG BOOL FAR PASCAL ScreenDlgProc ( HWND, WORD, WORD, LONG );
HELPDLG BOOL FAR PASCAL TopicsDlgProc ( HWND, WORD, WORD, LONG );
HELPDLG LONG FAR PASCAL ScreenWndProc ( HWND, WORD, WORD, LONG );
extern LPSTR FAR PASCAL lstrcpy ( LPSTR, LPSTR );
extern int FAR PASCAL lstrlen ( LPSTR );
[LISTING THIRTEEN]
/*************************************************************************
* FILE: helpdemo.h
* PURPOSE: include file for the help DLL demonstration window
*************************************************************************/
/************** strings **************************************************/
#define IDS_CLASS 0 /* String Table ID for the Class Name */
#define IDS_TITLE 1 /* String Table ID for the Title */
#define IDS_ABOUT 2 /* String Table ID for the About box */
/************** menus ****************************************************/
#define ABOUTBOX 3 /* About dialog resource ID */
#define IDM_HELP 1000 /* Menu resource ID */
[LISTING FOURTEEN]
NAME HELPDEMO
DESCRIPTION 'Help DLL Demonstration, Copyright 1988, mkj'
STUB 'WINSTUB.EXE'
CODE LOADONCALL MOVEABLE DISCARDABLE
DATA MOVEABLE MULTIPLE
HEAPSIZE 2048
STACKSIZE 4096
EXPORTS
WndProc @1
AboutDlgProc @2
[LISTING FIFTEEN]
/**********************************************************************
* FILE: helpdemo.rc
* PURPOSE: used with the helplib DLL for demonstration
**********************************************************************/
#include <style.h>
#include "helpdemo.h"
STRINGTABLE
BEGIN
IDS_CLASS "HelpDemo"
IDS_TITLE "Help Demonstration"
IDS_ABOUT "About..."
END
ABOUTBOX DIALOG 22, 17, 154, 75
STYLE WS_POPUP | WS_DLGFRAME
BEGIN
CTEXT "DLL Example" -1, 0, 5, 154, 8
CTEXT "Help Library Demonstration" -1, 0, 14, 154, 8
CTEXT "Version 1.00" -1, 30, 34, 94, 8
CTEXT "Copyright ) 1988, mkj" -1, 0, 47,154, 9
DEFPUSHBUTTON "Ok" IDOK, 61, 59, 32, 14, WS_GROUP
END
HelpDemo MENU
BEGIN
MENUITEM "\aF1=Help", IDM_HELP,HELP
END
HelpDemo ACCELERATORS
BEGIN
VK_F1, IDM_HELP, VIRTKEY
END
[LISTING SIXTEEN]
TOPICS_BOX DIALOG LOADONCALL MOVEABLE DISCARDABLE 28, 19, 206, 79
STYLE WS_DLGFRAME | WS_POPUP
BEGIN
CONTROL "", ID_LB_TOPICS, "listbox", LBS_NOTIFY | WS_BORDER | WS_VSCROLL | WS_CHILD | TABGRP, 12, 18, 144, 49
CONTROL "&Help", IDOK, "button", BS_DEFPUSHBUTTON | WS_TABSTOP | WS_CHILD | TABGRP, 165, 17, 32, 14
CONTROL "Cancel", IDCANCEL, "button", BS_PUSHBUTTON | WS_TABSTOP | WS_CHILD , 165, 43, 32, 14
CONTROL "Help Topics on DLL's", 103, "static", SS_LEFT | WS_CHILD, 12, 5, 100, 11
END
[LISTING SEVENTEEN]
HELP_BOX DIALOG LOADONCALL MOVEABLE DISCARDABLE 10, 9, 262, 131
STYLE WS_BORDER | WS_CAPTION | WS_POPUP | WS_SYSMENU | WS_VISIBLE
CAPTION "Help"
BEGIN
CONTROL "", ID_SCREEN_HELP, "Screen", WS_BORDER | WS_CHILD | TABGRP, 9, 9, 234, 90
CONTROL "", ID_SCROLL_HELP, "scrollbar", SBS_VERT | WS_CHILD | WS_CLIPSIBLINGS, 242, 9, 8, 90
CONTROL "&Next", ID_NEXT_HELP, "button", BS_DEFPUSHBUTTON | WS_TABSTOP | WS_CHILD, 76, 105, 44, 16
CONTROL "&Previous", ID_PREVIOUS_HELP, "button", BS_PUSHBUTTON | WS_TABSTOP | WS_CHILD, 139, 105, 44, 16
CONTROL "Cancel", IDCANCEL, "button", BS_PUSHBUTTON | WS_TABSTOP | WS_CHILD, 201, 105, 44, 16
CONTROL "&Topics", ID_TOPICS_HELP, "button", BS_PUSHBUTTON | WS_TABSTOP | WS_CHILD, 14, 105, 44, 16
END
[LISTING EIGHTEEN]
#
# FILE: helpdemo
# PURPOSE: make file for the helplib DLL demo
#
COMP = -c -AS -D LINT_ARGS -Os -Zp -Gsw -FPa
ASM =
.rc.res:
rc -r $*.rc
.c.obj:
cl $(COMP) $*.c
.asm.obj:
masm $(ASM) $*;
helpdemo.res: helpdemo.rc helpdemo.h
helpdemo.obj: helpdemo.c helpdemo.h
wndproc.obj: wndproc.c helpdemo.h
msgs.obj: msgs.c helpdemo.h helplib.h prothelp.h
helpdemo.exe: helpdemo.obj wndproc.obj msgs.obj helpdemo.res
link4 helpdemo+wndproc+msgs,/align:16,/map/li,slibw slibca helplib /NOE /co ,helpdemo.def
rc helpdemo.res
[LISTING NINETEEN]
/* **************************************
FILE: helplib.act
PURPOSE: example of specifying and loading
the library at run-time instead of
at link (link4). The code is written in
Actor, an object-oriented language for
developing MS-Windows applications.
************************************** */
/* **************************************
INITIALIZATION
************************************** */
/* define constants */
#define VSRUNTIME 300
#define CAVEATS 301
#define COOKBOOK 302
#define REF 303
#define A 500
#define B 501
#define C 502
!!
/* create a new C struct */
SCREEN := new(CStruct);
!!
init(SCREEN, #(
int wScreen 1
int wStart 1
int wEnd 1
));
!!
/* initialize help library */
HelpLib := new(Library); /* create new library */
HelpLib.name := "HELPLIB.EXE"; /* set the file name of the library */
add(HelpLib, #SCREEN, 0, #(1)); /* add the names of the exported
functions in the library that you
will call. The '0' is the return
type (0=int,1=long), and the
'#(1)' lists the arguments - one
long variable */
!!
/* load library */
load(HelpLib);
!!
/* **************************************
BODY
************************************** */
/* fill C Struct */
SCREEN[#wStart] := VSRUNTIME;
SCREEN[#wEnd] := REF;
SCREEN[#wScreen] := CAVEATS;
!!
/* call DLL to put up help dialog */
pcall(HelpLib.procs[#SCREEN], lP(SCREEN));
freeHandle(SCREEN);
!!
/* **************************************
CLEAN-UP
************************************** */
/* free the library */
free(HelpLib);
!!
[EXAMPLE 1]
caveats
As is usually the case in life, it takes a
little more to get a little more. This is
certainly true with DLL's. There are two big
differences between code in a DLL and code in a
standard runtime library under MS-DOS. The
first one is on the tip of the tongue of anyone
who has ventured into the DLL domain. This is
the SS != DS issue. The second concerns the
use of global variables.
Normally, when c code is compiled, it is
assumed that the data segment (DS) is the same
as the stack segment (SS). This is valid when
passing the address of a parameter to a
function for the small (ie: one code segment
and one data segment) and medium (ie: multiple
code segments and one data segment) model,
since only the 16-bit offset of addresses are
passed.
DLL's have their own data segment and use the
stack of the caller. In this case, the stack
segment does not equal the data segment
(SS!=DS) and the 16-bit offsets are not valid
addresses, since all automatic variables (ie:
parameters and local variables) are kept on the
stack, and all others (ie: global and static
variables) are contained in the data segment.
This means that any addresses passed to a
function must contain both the segment and
offset (ie: 32-bit far pointers).
Because of this, some of the standard c runtime
library functions cannot be used. These are
listed in an appendix of Microsoft's Software
Development Kit (SDK) for Windows. In general,
any of the buffered io functions (eg: fprintf,
fscanf, sscanf, etc.), exec (eg: execlp, execv,
etc.), and spawn (eg: spawnl, spawnv, etc.)
functions are off limits.
Because programs in DOS need not be re-entrant,
it is common to generously sprinkle code with
global veriables. This can be a source of
grief to the person who wishes to convert
existing code to work in a DLL. Although code
is not re-entrant, the data is. A DLL has only
one data segment which is shared by all
applications. Don't expect a variable that is
set by one function of the DLL to contain the
set value in another function. A common case
are plotting libraries. Usually the sequence
of calls consist of setting plot variables,
graphing the plot using the plot variables set
previously, then performing any cleanup.
Putting the plotting variables in global memory
assumes each application that makes this series
of calls has it's own data area to hold these
variables. If these retines reside in a DLL,
then the global variable that sets the x-origin
within the DLL is the same variable used by any
application that calls this routine. For
example, if two applications (A and B) co-
exist and application A makes calls to set the
plotting variables, then B does the same before
A can call to plot, the variables used by the
DLL will be set to B's preferences.
[EXAMPLE 2]
cookbook
Steps To Follow When Creating a DLL:
1. Create the resource file.
2. Create the library source files.
3. Make sure you have an initialization function.
4. Create the module definition file.
5. Create a make file to:
a. Compile the library and initialization source files.
b. Use the rc compiler to compile any resources.
c. Use the link4 linker to create the .EXE file.
d. Attach the resources to the .EXE file.
e. Use the implib tool to create an import library.
[EXAMPLE 3]
references
Two books are definite musts:
Programming Windows by Charles Petzold
Microsoft Press: 1988
852 pages jam-packed with Windows programming
tips and useful code. This is an incredible
source for Windows developers.
Inside OS/2 by Gordon Letwin
Microsoft Press: 1988
289 pages from the chief architect for systems
software at Microsoft. This book is great for
getting a feel for what OS/2 has to offer, and
the philosophy behind it. It also gives a good
feeling for the differences between the API for
Windows and OS/2 without getting bogged down in
the code.
[EXAMPLE 4]
versus run-time libraries
In the MS-DOS world, code is compiled and
linked with external libraries or object
modules to create an executable. Frequently,
routines in libraries are generic, consisting
of often used functions. An example of this is
the run-time library included with the
compiler. Each executable that calls a routine
from the library contains a copy of the code
for that function. Under typical DOS single-
tasking conditions, and assuming it doesn't
matter how large the executable file is, run-
time libraries are just fine.
Having each application carry around a copy of
common code is inefficient in a multitasking
system such as Windows. Windows is an
operating environment that sits on top of DOS
and creates a non-preemptive event driven
multatasking environment for its applications.
In fact, with Windows, this is even more
important since Windows is constrained to sit
on top of DOS, and the environment that DOS
sits in only allows 640K of memory (assuming
no expanded memory). In Windows, if multiple
instances of the same application are loaded,
they will share the same code space. However,
if multiple applications are loaded, code is
not shared. If each application calls the
same function to smooth data from a run-time
library, then Windows will allocate code space
For the smooth function for each application.
As any one who has run multiple applications
under Windows knows, memory is to Windows what
water is to the desert - a precious resource
that should not be waisted.
If a function resides in a DLL, then only one
copy will be loaded no matter how many
applications call it. This also keeps the
application's executable small by keeping the
common code out of each application. Not only
that, but since the code is dynamically loaded
at run time, as long as the parameter sequence
of the function call does not change, the
innards of a function in a dll can be changed
without forcing the application's executable
to be recompiled and relinked.
Loading the library at run time allows other
exciting opportunities. Some packages allow
functions in a dll to be called within their
program. This includes Actor from Whitewater,
Excel from Microsoft, and SQL Windows from
Gupta. This allows the developer to use his
warm and comfy functions in extremely powerful
existing applications. But wait, there's more!
DLL's need not contain any code or data at
all! They can also be completely made of
resources such as fonts, bitmaps, icons, or
cursors.