Category : C Source Code
Archive   : MULTINST.ZIP
Filename : MULTINST.C

 
Output of file : MULTINST.C contained in archive : MULTINST.ZIP
// ***************************************************************************
// File Name: multinst.c
//
// Source file for MULTINST Multi Instance DLL sample.
//
// Description of sample:
//
// Creates a multiple instance DLL, a DLL that maintains separate
// data for each task that links to it. This is done by maintaining
// a list of tasks that have linked to the DLL. Different tasks are
// identified by the value of their SS (Stack Segment). Data for
// each task is stored in a block of memory obtained through
// GlobalAlloc(). When a tasks calls a function in the DLL, the
// DLL looks up the task in its list, and gets the segment
// (selector) of the block of global memory that contains that tasks
// data. This segment address (selector) is then placed into the DS
// register. After this point all static data and the local heap
// are specific to the task that called the DLL.
//
// The first time a task calls into the DLL, a new block of memory is
// allocated for the data for that task. The initial values for the
// static variables are copied into the block, and a local heap is
// initialized.
//
// When a task that uses the DLL shuts down, it needs to call the
// UnregisterTask() function. This removes the task from the DLL,s
// list and frees the data associated with the task. If the task does
// not call UnregisterTask(), it is possible that later another task
// might link to the DLL that has the same SS as the first task. Since
// the first task did not unregister itself that SS will be associated
// with a DS that is no longer present, and will cause a UAE.
//
// The following 6 lines of code need to be placed at the beginning of
// each exported function in the DLL to load the corrected data segment.
//
// if((wDS = LoadInstanceData())==0) // Get DS for this instance
// return; // if DS==0 then we are out of
// // memory so return
// _asm{
// mov ax,wDS
// mov DS,ax
// }
//
// Description of functions:
// LibMain() - Saves the initial values of static variables
// and the initial size of the DataSegement
// and heap.
// StoreData() - Saves a string in the local heap.
// GetData() - Gets a previously stored string.
// FillHeap() - Allocates memory in the local heap until
// LocalAlloc() fails. Used to demonstrated
// that the local heap will grow.
// InitInstanceData() - Saves initial values of static variables
// and initializes list of tasks.
// LoadInstanceData() - Gets the segment address (selector) to the
// data for the task that called the DLL.
// LookUpTask() - Given the SS of the task, looks up the
// segment address (selector) for the data
// for the task. If the task is not in the
// list, this function returns zero.
// AddTask() - Allocates data for the task, initializes
// the data, and adds the task to the list.
// UnregisterTask() - Removes the current task from the task list.
// This needs to be called when the current
// task is shutting down.
//
// Development Team: Brian Scott
//
// Written by Microsoft Product Support Services, Windows Developer Support
// Copyright (c) 1991-1992 Microsoft Corporation. All rights reserved.
// ***************************************************************************



#include
#include "MULTINST.h"
#include
#include "globals.h"

// define the global variables

HANDLE hList = NULL; // handle to the list of tasks that have linked
// to the DLL
LPSTR lpInitialDS; // pointer to initial values of static variables
WORD cbInitialDSSize; // Size of initial Data Segment
WORD cbInitialHeapSize; // Size of initial heap
int nTasks = 0; // number of tasks currently linked to the DLL
HANDLE hData = NULL; // Handle in local heap to stored string


//*****************************************************************************
// FUNCTION: LibMain(HANDLE, WORD, WORD, LPSTR)
//
// PURPOSE : Is called by LibEntry. LibEntry is called by Windows when
// the DLL is loaded.
//*****************************************************************************

int FAR PASCAL LibMain (hModule, wDataSeg, cbHeapSize, lpszCmdLine)
HANDLE hModule;
WORD wDataSeg;
WORD cbHeapSize;
LPSTR lpszCmdLine;
{
if (cbHeapSize != 0) // If DLL data seg is MOVEABLE
UnlockData (0);


cbInitialHeapSize = cbHeapSize;
return (InitInstanceData(wDataSeg));
}


// **************************************************************************
//
// StoreData()
//
// Purpose:
//
// Loads Instance Data for the calling task and then stores a string in
// the local heap.
//
// Parameters:
//
// LPSTR szAppEditString - long pointer to the string to be stored in the
// local heap.
//
// Return Value:
//
// None
//
// History: Date Author Reason
// 10/19/91 briansc Created
//
// **************************************************************************
void FAR PASCAL StoreData (LPSTR szAppEditString)
{
PSTR szEditString;
WORD wDS;

if ((wDS = LoadInstanceData()) == 0) // Get DS for this instance
return; // if DS==0 then we are out of
// memory so return


_asm{
mov ax,wDS
mov DS,ax
}

if (hData)
hData = LocalReAlloc(hData, lstrlen(szAppEditString), LMEM_MOVEABLE);
else
hData = LocalAlloc(LMEM_MOVEABLE, lstrlen(szAppEditString));

szEditString = LocalLock(hData);
lstrcpy(szEditString, szAppEditString);
LocalUnlock(hData);
}

// **************************************************************************
//
// GetData()
//
// Purpose:
//
// Loads Instance Data for the calling task and then copies the string
// stored in the DLL into a string provided by the application.
//
// Parameters:
//
// LPSTR - Long pointer to the string in app to hold the data in the DLL
//
// Return Value:
//
//
// History: Date Author Reason
// 10/19/91 briansc Created
//
// **************************************************************************
void FAR PASCAL GetData (LPSTR lpszAppEditString)
{
PSTR pszEditString;
WORD wDS;

if ((wDS = LoadInstanceData()) == 0) // Get DS for this instance
return; // if DS==0 then we are out of
// memory so return


_asm{
mov ax,wDS
mov DS,ax
}

if (hData)
{
pszEditString = LocalLock(hData);
lstrcpy(lpszAppEditString, pszEditString);
LocalUnlock(hData);
}
else
lstrcpy(lpszAppEditString, "No Data in DLL");
}

// **************************************************************************
// LoadInstanceData()
//
// Purpose:
//
// Maintains a list of tasks that have called the application. If the
// task is new to the DLL,then the a data segment is allocated for the
// application, otherwise, the data segment is looked up in the list.
//
//
// Parameters:
//
// None
//
// Return Value:
//
// wDS - Segment address (selector) of data for the task
// 0 if could not allocate memory for the data segment
//
// History: Date Author Reason
// 10/19/91 briansc Created
//
// ***************************************************************************

WORD LoadInstanceData (void)
{
WORD wSS;
WORD wDS;

// get SS
_asm{
mov ax,SS
mov wSS,ax
}

// look up the current task

wDS = LookUpTask(wSS);
if (!wDS)
// Add the new task if task is not in list
wDS = AddTask(wSS);
return (wDS);
}

// **************************************************************************
// InitInstanceData()
//
// Purpose:
//
// Called by LibMain when DLL starts up. Allocates a block of memory and
// saves initial values of static variables in that block. Also initializes
// the list of tasks
//
// Parameters:
//
// wDataSeg - the data segment of the DLL.
//
// Return Value:
//
// int - 1 if the initial instance data was saved correctly.
// 0 if could not allocate memory to save initial instance data
//
// History: Date Author Reason
// 10/19/91 briansc Created
//
// ***************************************************************************
int InitInstanceData (WORD wDataSeg)
{
HANDLE hDS; // Handle to Data Segment
WORD wSize; // size of data segment
HANDLE hInitialDS; // block that holds the initial DS

// Save initial static data

hDS = GlobalHandle(wDataSeg);
cbInitialDSSize = GlobalSize(hDS);

if (!(hInitialDS = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE,
cbInitialDSSize - cbInitialHeapSize)))
{
MemoryError();
return (0);
}
lpInitialDS = GlobalLock(hInitialDS);
_fmemcpy(lpInitialDS, (LPSTR)(MAKELONG(0,wDataSeg)), cbInitialDSSize -
cbInitialHeapSize);

// Initialize the list
hList = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT,
sizeof(TASKENT) * INIT_LIST_SIZE);

return (1);
}

// **************************************************************************//
// LookUpTask()
//
// Purpose:
//
// Looks up the task in the task list.
//
// Parameters:
//
// wSS - the stack segment of the calling task. Used to identify the
// task.
//
// Return Value:
//
// wDS - the segment address (selector) of the data associated with
// this task or zero if the task is not in the list.
//
//
// History: Date Author Reason
// 10/19/91 briansc Created
//
// ***************************************************************************
WORD LookUpTask (WORD wSS)
{
int i;
TASKENT near *pTaskEnt;

pTaskEnt = (TASKENT near *)LocalLock(hList);

for (i = 0; i < nTasks; ++i)
if (pTaskEnt[i].wSS == wSS)
return (pTaskEnt[i].wDS);

return (NULL);
}

// **************************************************************************
//
// AddTask()
//
// Purpose:
//
// Adds that task to the task list, allocates memory for the tasks data,
// and initializes the data.
//
// Parameters:
//
// wSS - the stack segment of the calling task. Used to identify the
// task.
//
// Return Value:
//
// wDS - the segment address (selector) of the data associated with
// this task.
//
// History: Date Author Reason
// 10/19/91 briansc Created
//
// ***************************************************************************

WORD AddTask (WORD wSS)
{
HANDLE hDS;
WORD wDS;
TASKENT near *pTaskEnt;
LPSTR lpDS;
int nListSize;

// Make sure the list is big enough to hold this entry

nListSize = LocalSize(hList) / sizeof(TASKENT);
if (nListSize <= nTasks)
{
int i;

hList = LocalReAlloc(hList, (nListSize + INIT_LIST_SIZE) *
sizeof(TASKENT), LMEM_MOVEABLE);
pTaskEnt = (TASKENT near *)LocalLock(hList);
for (i = nListSize; i < nListSize + INIT_LIST_SIZE; ++i)
{
pTaskEnt[i].wSS = 0;
pTaskEnt[i].wDS = 0;
}
LocalUnlock(hList);
}

// get a global memory block for this instance
if (!(hDS = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, cbInitialDSSize)))
{
MemoryError();
return (0);
}
lpDS = GlobalLock(hDS);
_fmemcpy(lpDS, lpInitialDS, cbInitialDSSize - cbInitialHeapSize);
wDS = HIWORD((LONG)lpDS);
LocalInit(wDS, 0, cbInitialHeapSize);

pTaskEnt = (TASKENT near *)LocalLock(hList);
pTaskEnt[nTasks].wSS = wSS;
pTaskEnt[nTasks].wDS = wDS;
LocalUnlock(hList);
++nTasks;

return (wDS);
}



// **************************************************************************
//
// MemoryError()
//
// Purpose:
//
// Informs the user that the Global Heap is out of memory
//
// Parameters:
//
// None
//
// Return Value:
//
// None
//
// History: Date Author Reason
// 10/19/91 briansc Created
//
// ***************************************************************************
void MemoryError (void)
{
MessageBox(GetFocus(), "Out of Memory in DLL", "Memory Error", MB_OK);
}



// **************************************************************************
//
// UnregisterTask()
//
// Purpose:
//
// Removes a task from the task list and frees the memory associated with
// that task.
//
// Parameters:
//
// None
//
// Return Value:
//
// None
//
// History: Date Author Reason
// 10/19/91 briansc Created
//
// ***************************************************************************

void FAR PASCAL UnregisterTask ()
{
int i;
TASKENT near *pTaskEnt;
WORD wSS;

_asm{
mov ax,SS
mov wSS,ax
}

pTaskEnt = (TASKENT near *)LocalLock(hList);

for (i = 0; i < nTasks; ++i)
{
if (pTaskEnt[i].wSS == wSS)
break;
}

// if the task was found
if(i {
// free the DS
GlobalFree(LOWORD(GlobalHandle(pTaskEnt[i].wDS)));

// remove the entry from the list
--nTasks;
pTaskEnt[i].wSS = pTaskEnt[nTasks].wSS;
pTaskEnt[i].wDS = pTaskEnt[nTasks].wDS;
}
}

// **************************************************************************
//
// FillHeap()
//
// Purpose:
//
// Loads Instance Data for the calling task and fills the local heap with
// 1024 byte blocks.
//
// Parameters:
//
// None
//
// Return Value:
//

// int - number of 1024 byte blocks allocated,
// zero if out of memory
//
// History: Date Author Reason
// 10/19/91 briansc Created
//
// ***************************************************************************
int FAR PASCAL FillHeap (void)
{
int n = 0;
WORD wDS;

if ((wDS = LoadInstanceData()) == 0) // Get DS for this instance
return(0); // if DS==0 then we are out of
// memory so return

_asm{
mov ax,wDS
mov DS,ax
}

// Fill the local heap
while (LocalAlloc(LMEM_MOVEABLE, 1024))
++n;
return (n);
}



/* END OF FILE */


  3 Responses to “Category : C Source Code
Archive   : MULTINST.ZIP
Filename : MULTINST.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/