home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mega CD-ROM 1
/
megacd_rom_1.zip
/
megacd_rom_1
/
MAGAZINE
/
MSJOURNA
/
MSJV3_3.ZIP
/
DLLCODE.ALL
next >
Wrap
Text File
|
1988-04-28
|
21KB
|
804 lines
Microsoft Systems Journal
Volume 3; Issue 3; May, 1988
Code Listings For:
DLL_CHAT; DLL_LIB; CHATMEM
pp. 27-48
Author(s): Ross M. Greenberg
Title: Design Concepts and Considerations in Building an OS/2
Dynamic-Link Library
Figure 7
========
DLL_CHAT DEF File
=================
IMPORTS CHATLIB.login
IMPORTS CHATLIB.get_msg_cnt
IMPORTS CHATLIB.send_msg
IMPORTS CHATLIB.logout
IMPORTS CHATLIB.get_msg
==============================================================================
/* Header file for CHAT */
struct gdtinfoarea{
unsigned long time;
unsigned long milliseconds;
unsigned char hours;
unsigned char minutes;
unsigned char seconds;
unsigned char hundreths;
unsigned timezone;
unsigned timer_interval;
unsigned char day;
unsigned char month;
unsigned year;
unsigned char day_of_week;
unsigned char major_version;
unsigned char minor_version;
unsigned char revision_number;
unsigned char current_screen_group;
unsigned char max_num_of_screengrps;
unsigned char huge_selector_shift_count;
unsigned char protect_mode_indicator;
unsigned foreground_process_id;
unsigned char dynamic_variation_flag;
unsigned char maxwait;
unsigned minimum_timeslice;
unsigned maximum_timeslice;
unsigned boot_drive;
unsigned char reserved[32];
};
struct ldtinfoarea{
unsigned current_process_pid;
unsigned parent_pid;
unsigned priority_of_current_thread;
unsigned thread_id_of_current_thread;
unsigned screen_group;
unsigned subscreen_group;
unsigned current_process_is_in_fg;
};
==============================================================================
/********************************************************************
* DLL_CHAT.C - A demonstration program using a demo DLL
*
* (C) 1988, By Ross M. Greenberg for Microsoft Systems Journal
*
* This is the main body of the CHAT program, interfacing with
* and calling the DLL as if it were a bunch of routines
* available with a far call: which it is!
*
* Compile with:
* cl /c chat.c
* link chat,chat,,slibce+doscalls,chat
*
* Remember: move the DLL itself into your DLL library directory
*
********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "chat.h"
#define TRUE 1
#define FALSE 0
#define OK TRUE
#define NOT_OK FALSE
#define MAX_MSG 100
#define MAX_MSG_LEN 80
#define NULLP (void *)NULL
/* The following OS/2 system calls are made in this module: */
extern far pascal dosexitlist();
extern far pascal dossleep();
/* The following DLL system calls are made in this module: */
extern far _loadds pascal login();
extern far _loadds pascal logout();
extern far _loadds pascal get_msg_cnt();
extern far _loadds pascal get_msg();
extern far _loadds pascal send_msg();
/********************************************************************
* This is where the messages are stored, once received and
* formatted. This could probably be replaced easily with a call
* to calloc(), but then we wouldn't have to block on being a
* background process
********************************************************************/
char msg_array[MAX_MSG + 1][MAX_MSG_LEN];
/* Must be global so that before_death() can access it to logout */
int my_id = 0;
#define MAX_SLEEP 2
/********************************************************************
* before_death()
*
* Called the coins are lowered onto the eyes of this invokation
* of CHAT. Any exit will cause this routine to be called. After
* this routine calls the DLL logout procedure, it removes calls
* the next exitroutine in the exit list.
********************************************************************/
void far before_death()
{
logout(my_id);
dosexitlist(3, before_death);
}
/********************************************************************
* main()
*
* After logging in (which returns a unique login id), the
* before_death() routine is added onto the exitlist. Then the
* main loop:
*
* If there are any messages, read them into out memory buffer
* (provided there is room) and kick up the count. After
* retrieving all the msgs which will fit, call the display
* routine for each msg. Zero the count of messages when done.
*
* Every couple of seconds, sleep for a little while (as if a
* human typing on a keyboard), then send the message to all
* other members of CHAT.
*
* CHAT can only be exited (in its current form) with a
* control-C or error condition.
********************************************************************/
main()
{
int msg_cnt = 0;
int msg_id = 0;
int lp_cnt;
char tmp_buf[MAX_MSG_LEN];
int m_cnt;
printf("Logged into CHAT as user:%d\n", my_id = login());
dosexitlist(1, before_death);
while (TRUE)
{
for (m_cnt = get_msg_cnt(my_id); m_cnt ; m_cnt--)
{
get_msg(my_id, (char far *)tmp_buf);
if (msg_cnt <= MAX_MSG)
sprintf(msg_array[msg_cnt++],"(%d)%s",my_id,tmp_buf);
}
if (ok_to_disp())
{
for (lp_cnt = 0 ; lp_cnt < msg_cnt; lp_cnt++)
disp_msg(msg_array[lp_cnt]);
if (msg_cnt > MAX_MSG)
disp_msg("Looks like you might have lost some")
disp_msg(" messages while you were away\n");
msg_cnt = NULL;
}
if (rand() % (my_id + 1))
{
dossleep((long)(rand() % MAX_SLEEP) * 1000L);
sprintf(tmp_buf, "Test message #%d from Session #%d\n",
msg_id++, my_id);
if (send_msg(my_id, (char far *)tmp_buf) == NOT_OK)
printf("?Can't send a message....\n");
}
}
}
disp_msg(ptr)
char *ptr;
{
printf("%s", ptr);
fflush(stdout);
}
extern far pascal dosgetinfoseg();
ok_to_disp()
{
struct gdtinfoarea far *gdt;
struct ldtinfoarea far *ldt;
unsigned gseg;
unsigned lseg;
dosgetinfoseg((char far *)&gseg, (char far *)&lseg);
gdt = (struct gdtinfoarea far *)((long)gseg << 16);
ldt = (struct ldtinfoarea far *)((long)lseg << 16);
return( gdt->foreground_process_id == ldt->parent_pid);
}
Figure 8
========
CHATLIB DEF File
================
LIBRARY CHATLIB INITGLOBAL
DATA SINGLE SHARED
EXPORTS login
EXPORTS get_msg_cnt
EXPORTS send_msg
EXPORTS logout
EXPORTS get_msg
==============================================================================
/********************************************************************
* CHATLIB.C - A demonstration Dynamic Link Library
*
* (C) 1988, By Ross M. Greenberg for Microsoft Systems Journal
*
* This DLL, when used with the CHAT program acts as a central
* repository for all messages being passed
*
* Compile with:
*
* cl /AL /Au /Gs /c chatlib.c
*
* Note - Though broken here the following two lines are entered
* as one line:
*
* link startup+chatlib+chatmem,chatlib.dll,,llibcdll+doscalls,
* chatlib/NOE
*
* Remember to move the DLL itself into your DLL library directory
*
********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <dos.h>
#define TRUE 1
#define FALSE 0
#define OK TRUE
#define NOT_OK FALSE
#define NULLP ((char *)NULL)
#define GET_SEM (dossemrequest(&semaphore, -1L))
#define RLS_SEM (dossemclear(&semaphore))
/* The following OS/2 system calls are made in this module: */
extern far pascal dossemrequest();
extern far pascal dossemclear();
/* The following external calls are made in this module: */
char *my_calloc();
/* This semaphore used to coordinate access to "critical" areas */
long semaphore = 0;
/*******************************************************************
* This structure starts defines the members of the linked list
* which starts at master_ptr. Once a structure is allocated,
* it is never released, although the character array member
* msg_ptr points to will be released when the message is no longer
* needed
********************************************************************/
#define MSG struct _msg
MSG{
MSG *next_ptr; /* Point to next MSG, or NULLM */
char *msg_ptr; /* Point to the actual message */
int msg_len; /* length of the message - optional */
unsigned f_word; /* flag_word. When set to 0xfff */
/* all chat members have seen this */
/* message, so it can be freed */
};
int flag_word = 0xffff; /* This is the word that f_word is */
/* set to initially. It is modified */
/* so that each bit is "off" if that*/
/* "user" is logged in */
#define NULLM ((MSG *)NULL)
MSG *master_ptr = NULLM; /* Where the linked list begins */
/********************************************************************
* new_msg_struct(pointer to last MSG)
*
* Allocates a new MSG, initializes the contents of the structure,
* and sets the linked list if not the first time called
* (last_msg != NULLM)
*
* Returns a pointer to the structure allocated, NULLM if an error
********************************************************************/
MSG *new_msg_struct(MSG *last_msg)
{
MSG *tmp_ptr;
if ((tmp_ptr = (MSG *)my_calloc(sizeof(MSG), 1)) == NULLM)
return(NULLM);
tmp_ptr->next_ptr = NULLM;
tmp_ptr->msg_ptr = NULLP;
tmp_ptr->msg_len = NULL;
tmp_ptr->f_word = flag_word;
if (last_msg != NULLM)
last_msg->next_ptr = tmp_ptr;
return(tmp_ptr);
}
/********************************************************************
* initialize()
*
* Called either by the initialization routine of the DLL, or by the
* first login. It allocates the first MSG structure, then allocates
* and sets up for the next member
********************************************************************/
void far _loadds pascal initialize()
{
if ((master_ptr = new_msg_struct(NULLP)) == NULLM)
{
printf("Couldn't allocate MSG memory for header...\n");
exit(1);
}
new_msg_struct(master_ptr);
}
/********************************************************************
* login()
*
* If the master MSG structure hasn't been allocated already by
* and earlier call to initialize() (by the DLL initialize routine),
* then make the call now. Memory has already been allocated,
* therefore, so now give ourselves access to the segment we've
* allocated.
*
* Get the next free bit slot in the flag word, set it to indicate
* it's in use, then return our login id.
********************************************************************/
int far _loadds pascal login()
{
int log_id;
int tmp_msk;
if (master_ptr == NULLM)
{
printf("Init in login\n");
initialize();
}
my_getseg();
GET_SEM;
for (log_id= 0 ; log_id < 16 ; log_id++)
{
tmp_msk = mask(log_id);
if (flag_word & tmp_msk)
{
flag_word &= ~tmp_msk;
RLS_SEM;
return(log_id);
}
}
RLS_SEM;
printf("Login slots all used up!\n");
exit(1);
}
/********************************************************************
* get_msg_cnt(login_id)
*
* For every MSG structure in the linked list with an associated
* message attached to it, increment a counter if the id in question
* hasn't received it yet, then return that counter when we fall off
* the end.
********************************************************************/
int far _loadds pascal get_msg_cnt(int id)
{
MSG *tmp_ptr;
int tmp_cnt = 0;
int tmp_msk = mask(id);
GET_SEM;
for(tmp_ptr = master_ptr; tmp_ptr; tmp_ptr = tmp_ptr->next_ptr)
{
if (!(tmp_ptr->f_word & tmp_msk))
if (tmp_ptr->msg_len)
tmp_cnt++;
}
RLS_SEM;
return(tmp_cnt);
}
/********************************************************************
* send_msg(login_id, pointer_to_message)
*
* If there are no other "chatter's" logged in, simply return.
* (Flag_word or'ed with our mask would be 0xfff)
*
* Find a free MSG structure (guaranteed to have at least one, since
* every write leaves a free one allocated if its the last one in
* the linked list.
*
* Allocate memory for the message, copy the message into it, then
* assign the pointer in the structure and the length of the message.
* Finally, allocate a new structure if required.
********************************************************************/
int far _loadds pascal send_msg(int id, char far *ptr)
{
MSG *tmp_ptr = master_ptr;
int tmp_len = strlen(ptr) + 1;
if ((flag_word | mask(id)) == 0xffff)
return(OK);
GET_SEM;
while (tmp_ptr->msg_len)
tmp_ptr = tmp_ptr->next_ptr;
if ((tmp_ptr->msg_ptr = my_calloc(tmp_len, 1)) == NULLP)
{
printf("Can't allocate %d bytes for msg\n", tmp_len);
RLS_SEM;
return(NOT_OK);
}
strcpy(tmp_ptr->msg_ptr, ptr);
tmp_ptr->msg_len = tmp_len;
tmp_ptr->f_word = (flag_word | mask(id));
if (tmp_ptr->next_ptr == NULLM)
{
if (new_msg_struct(tmp_ptr) == NULLM)
{
printf("Can't allocate new MSG_header\n");
free_msg(tmp_ptr);
RLS_SEM;
return(NOT_OK);
}
}
RLS_SEM;
return(OK);
}
/********************************************************************
* logout(login_id)
*
* Mark every mesage as read (freeing them if now "totally" read),
* reset the flag word, and then indicate that the logout worked.
********************************************************************/
int far _loadds pascal logout(int id)
{
MSG *tmp_ptr;
int tmp_msk = mask(id);
GET_SEM;
for(tmp_ptr = master_ptr; tmp_ptr; tmp_ptr = tmp_ptr->next_ptr)
mark_msg(id, tmp_ptr);
flag_word |= mask(id);
RLS_SEM;
printf("In logout ... Hit a Key:");fflush(stdout);
getch();
printf("\n\n\n\n");
return(0);
}
/********************************************************************
* get_msg(login_id, pointer to buffer)
*
* Find the first message the login_id hasn;t read, then
* strcpy it into the buffer supplied. Then mark the message as
* read (freeing as required).
********************************************************************/
int far _loadds pascal get_msg(int id, char far *ptr)
{
MSG *tmp_ptr = master_ptr;
int tmp_msk = mask(id);
GET_SEM;
for(tmp_ptr = master_ptr; tmp_ptr; tmp_ptr = tmp_ptr->next_ptr)
{
if (!(tmp_ptr->f_word & tmp_msk))
{
strcpy(ptr, tmp_ptr->msg_ptr);
mark_msg(id, tmp_ptr);
RLS_SEM;
return(TRUE);
}
}
RLS_SEM;
return(FALSE);
}
/********************************************************************
* mark_msg(login id, pointer to message structure)
*
* Mark our bit in the MSG f_word as set. If then set to 0xffff,
* the message is "totally" read, so free it.
*
* ******************************************************************
*
* free(pointer to message structure)
*
* If there is a string associated with this structure, free the
* memory so used, then zero out the pointer and the msg_len
********************************************************************/
mark_msg(int id, MSG *ptr)
{
ptr->f_word |= mask(id);
if (ptr->f_word == 0xffff)
free_msg(ptr);
}
free_msg(MSG *ptr)
{
if (ptr->msg_ptr)
my_free(ptr->msg_ptr);
ptr->msg_ptr = NULLP;
ptr->msg_len = NULL;
}
/* GENERAL ROUTINES */
/* This routine merely returns with the bit corresponding
* to our login set
*/
mask(int log_id)
{
return(1 << (log_id - 1));
}
==============================================================================
Additional Module for CHATLIB
=============================
/********************************************************************
* CHATMEM.C - Memory allocation routines for shared DLL memory
*
* (C) 1988, By Ross M. Greenberg for Microsoft Systems Journal
*
* This module conatins three functions. Allocation of memory,
* de-allocation of memory and the getseg call.
*
* The current ANSI calloc/alloc/malloc sequence does not allow for
* an additional parameter to specify if memory requested through
* these functions is to be sharable or private. Therefore the MSC
* library calls all allocate private memory.
*
* These routines allocate a 64K chunk of memory, requested from OS/2
* as a sharable chunk, then dole it out using the DosSub allocation
* calls.
*
* Only one 64K chunk is allocated: if more memory is desired an
* additional call to dosallocseg would have to be made and all
* sessions already logged in given access to the chunk. Out of
* laziness, that was not done for these demonsttration routines.
*
*
* Compile with:
*
* cl /AL /Au /Gs /c chatmem.c
*
* Note - Though broken here, the following two lines are entered
* as one line:
*
* link startup+chatlib+chatmem,chatlib.dll,,llibcdll+doscalls,
* chatlib/NOE
*
* Remember to move the DLL itself into your DLL library directory
*
********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <dos.h>
#define TRUE 1
#define FALSE 0
/* The following OS/2 system calls are made in this module: */
extern far pascal dosallocseg();
extern far pascal dosfreeseg();
extern far pascal dossuballoc();
extern far pascal dossubset();
extern far pascal dossubfree();
extern far pascal dosgetseg();
extern far pascal dossemrequest();
extern far pascal dossemclear();
#define NULLP (char *)NULL
/* This semaphore is so that we don't hurt ourselves as we allocate
* and deallocate memory
*/
long memory_semaphore = NULL;
/* This is the actual selector which the 64K dosallocseg()
* call returns
*/
unsigned major_selector = NULL;
/********************************************************************
* my_calloc(number_of_items,size_of_item)
*
* Emulates the more typical calloc call, but returns memory which
* can later be allocated as sharable.
*
* After the first call (which causes a 64K chunk to be allocated),
* all subsequent calls cause a dossuballoc call to be made, and
* a long pointer to the returned memory to be created and returned
*
* The 64K chunk must be initialized by the dossubset call before it
* can be used by other dossub functions.
*
* Because the dossubfree call requires a size, the size requested
* plus the sizeof an int is actually allocated and the size of the
* total request is then stored in the first two bytes of the
* returned character array. The ptr returned, however, is this
* memory location plus the initial sizeof and int -- therefore the
* bookkeeping is transparent to the application task.
********************************************************************/
char *
my_calloc(size1, size2)
int size1;
int size2;
{
unsigned long selector;
int stat;
char *ptr;
int sizeit = (size1 * size2) + sizeof(int);
dossemrequest(&memory_semaphore, -1L);
if (!major_selector)
{
if (stat = dosallocseg(0, &major_selector, 3))
{
printf("dosalloc error:%d\n", stat);
dossemclear(&memory_semaphore);
return(NULLP);
}
if (stat = dossubset(major_selector, 1, 0))
{
printf("Error in dossubset:%d\n", stat);
dossemclear(&memory_semaphore);
return(NULLP);
}
}
selector = 0;
if (stat = dossuballoc(major_selector, &selector, sizeit))
{
printf("dossuballoc error:%d\n", stat);
dossemclear(&memory_semaphore);
return(NULLP);
}
dossemclear(&memory_semaphore);
ptr = (char *)(((long)major_selector << 16) + (long)selector);
memset(ptr, (char)NULL, sizeit);
*(int *)ptr = sizeit;
return(ptr + sizeof(int));
}
/********************************************************************
* my_free(pointer_to_a_character_array_previously_my_calloc'ed)
*
* Subtract sizeof an int from the pointer, dereference as an
* int, then free that number of bytes.
*
********************************************************************/
my_free(ptr)
char *ptr;
{
int stat;
ptr -= sizeof(int);
dossemrequest(&memory_semaphore, -1L);
if (stat = dossubfree(major_selector, FP_OFF(ptr), *(int *)ptr))
{
printf("Error freeing: %lx\n", ptr);
exit(1);
}
dossemclear(&memory_semaphore);
}
/********************************************************************
* my_getseg()
*
* Causes the memory affilaited with the major_selector to become
* accessable to this process.
********************************************************************/
my_getseg()
{
int stat;
if (stat=dosgetseg(major_selector))
printf("Error on getseg:%d\n", stat);
return(stat);
}