mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
468 lines
11 KiB
468 lines
11 KiB
/*****************************************************************************\
|
|
*
|
|
* Name: Dosdll.c
|
|
*
|
|
* Purpose: Source code for LoadModR, GetProcAddrR and UnloadModR
|
|
* Must be compiled for Large model with no stack checking
|
|
* (/AL /Gs switches)
|
|
*
|
|
* Revision History:
|
|
* 44/18/91 - Dave Steckler - Created
|
|
* 05/01/91 - Dave Steckler - Call the entry point (indirect call
|
|
* to DOSDLLInit)
|
|
*
|
|
\*****************************************************************************/
|
|
|
|
#include <string.h>
|
|
#include <dos.h>
|
|
#include <malloc.h>
|
|
#include <fcntl.h>
|
|
#include <stdarg.h>
|
|
#include <dos.h>
|
|
|
|
#define INCL_DOSDLL_SUPFUNCS
|
|
#include <dosdll.h>
|
|
#include "llibcd.h"
|
|
|
|
struct ModuleHandle *
|
|
_FindModuleHandle(
|
|
char * ModuleName
|
|
);
|
|
|
|
char *
|
|
FindBaseName(
|
|
char * PathName
|
|
);
|
|
|
|
struct ExeHeader
|
|
{
|
|
unsigned short usExeSignature;
|
|
unsigned short usFileLenMod512;
|
|
unsigned short usFileLenInPages;
|
|
unsigned short usNumRelocItems;
|
|
unsigned short usHeaderSizeInParas;
|
|
unsigned short usMinParasNeeded;
|
|
unsigned short usMaxParasNeeded;
|
|
unsigned short usStackSegDisplacement;
|
|
unsigned short usSPContentAtStartup;
|
|
unsigned short usWordChecksum;
|
|
unsigned short usIPContentAtStartup;
|
|
unsigned short usCodeSegDisplacement;
|
|
unsigned short usFirstRelocItemOffset;
|
|
char chOverlayNumber;
|
|
};
|
|
|
|
struct ModuleHandle
|
|
{
|
|
unsigned short usModuleLoadSeg;
|
|
unsigned short RefCount;
|
|
struct FunctionTable * pFunctionTable;
|
|
struct ModuleHandle * pNext;
|
|
char ModuleName[8+1+3+1];
|
|
};
|
|
|
|
/*
|
|
* This routine does the work of loading the DLL into memory and fixing
|
|
* up pointers.
|
|
*/
|
|
|
|
unsigned short LoadOvr( char * pszFunction, int iLoadSeg);
|
|
|
|
#define MAX_FILE_NAME_LEN 128
|
|
|
|
#define PARAGRAPH_SIZE(x) ((sizeof(x)+15)/16)
|
|
|
|
struct ModuleHandle * LoadedModuleList;
|
|
|
|
char DllDefaultExtension[] = ".dll";
|
|
|
|
/*****************************************************************************\
|
|
*
|
|
* LoadModR - Loads a module (DLL) into memory and returns a handle for it.
|
|
*
|
|
\*****************************************************************************/
|
|
|
|
/*
|
|
** Defined by Visual C++; it points to the full path of the executable.
|
|
*/
|
|
extern char __far * _pgmptr;
|
|
|
|
unsigned short DLL_ENTRY
|
|
LoadModR( char * pszModule, HINSTANCE * pulHandle)
|
|
{
|
|
unsigned short usRet;
|
|
unsigned short usLoadSeg;
|
|
char * BaseName;
|
|
char pszNewMod[MAX_FILE_NAME_LEN];
|
|
char pszFullFileName[MAX_FILE_NAME_LEN];
|
|
int iHandle;
|
|
struct ExeHeader ExeHdr;
|
|
unsigned short (*pfnDLLInit)( struct FunctionTable **ppFT );
|
|
struct ModuleHandle * pModuleHandle;
|
|
unsigned short usFileParagraphs;
|
|
|
|
/*
|
|
* Look for the module in the loaded list. _FindModuleHandle will
|
|
* append ".dll" to the module name if no extension is present.
|
|
*/
|
|
strcpy(pszNewMod, pszModule);
|
|
|
|
BaseName = FindBaseName(pszNewMod);
|
|
|
|
pModuleHandle = _FindModuleHandle(BaseName);
|
|
|
|
/*
|
|
* If the module is loaded, just increment the refcount, otherwise
|
|
* load the module.
|
|
*/
|
|
|
|
if (pModuleHandle)
|
|
{
|
|
pModuleHandle->RefCount++;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
** First, look for it in the directory containing the program.
|
|
**
|
|
*/
|
|
{
|
|
char * Slash;
|
|
|
|
_fstrcpy(pszFullFileName, _pgmptr);
|
|
Slash = strrchr(pszFullFileName, '\\');
|
|
strcpy(Slash+1, BaseName);
|
|
usRet = _dos_open(pszFullFileName, O_RDONLY, &iHandle );
|
|
}
|
|
|
|
/*
|
|
** Next, try to find the DLL on our PATH.
|
|
*/
|
|
|
|
if (usRet != 0)
|
|
{
|
|
usRet = dd_FindFileOnPath( pszNewMod, pszFullFileName, "PATH");
|
|
if (usRet != NO_ERROR)
|
|
{
|
|
return ERROR_FILE_NOT_FOUND;
|
|
}
|
|
|
|
usRet = _dos_open(pszFullFileName, O_RDONLY, &iHandle );
|
|
if (usRet != 0)
|
|
{
|
|
return usRet;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Read in the exe header.
|
|
*/
|
|
|
|
_asm
|
|
{
|
|
lea dx, ExeHdr
|
|
mov bx, iHandle
|
|
mov cx, size ExeHdr
|
|
mov ah, 03fh
|
|
int 21h
|
|
mov usRet,0
|
|
adc usRet,0 ; usRet != 0 if carry set -> means dos error
|
|
}
|
|
|
|
if (usRet != 0)
|
|
{
|
|
return usRet;
|
|
}
|
|
|
|
_dos_close( iHandle );
|
|
|
|
|
|
/*
|
|
* The amount of memory we need is the size of the file minus
|
|
* the size of the exe header plus the minimum extra space needed. First,
|
|
* start out with the length of the file (32 is the number of paragraphs
|
|
* in a page).
|
|
*/
|
|
|
|
usFileParagraphs = ((ExeHdr.usFileLenInPages) * 32) +
|
|
BYTES_TO_PARAGRAPHS(ExeHdr.usFileLenMod512);
|
|
|
|
/*
|
|
* Next add in the minimum extra space needed.
|
|
*/
|
|
|
|
usFileParagraphs += ExeHdr.usMinParasNeeded;
|
|
|
|
/*
|
|
* Now subtract out the size of the header.
|
|
*/
|
|
|
|
usFileParagraphs -= ExeHdr.usHeaderSizeInParas;
|
|
|
|
/*
|
|
* We will use the beginning of the buffer as space for the module
|
|
* handle, so allow space for it.
|
|
*/
|
|
|
|
usFileParagraphs += PARAGRAPH_SIZE(struct ModuleHandle);
|
|
|
|
/*
|
|
* Allocate this much memory. It needs to be paragraph aligned so use
|
|
* _dos_allocmem.
|
|
*/
|
|
|
|
usRet = _dos_allocmem( usFileParagraphs, &usLoadSeg );
|
|
if (usRet != 0)
|
|
return usRet;
|
|
|
|
/*
|
|
* Point the handle at its memory and advance the load segment.
|
|
*/
|
|
FP_SEG(pModuleHandle) = usLoadSeg;
|
|
FP_OFF(pModuleHandle) = 0;
|
|
|
|
usLoadSeg += PARAGRAPH_SIZE(struct ModuleHandle);
|
|
|
|
/*
|
|
* Load the file into memory.
|
|
*/
|
|
|
|
usRet = LoadOvr( pszFullFileName, usLoadSeg );
|
|
|
|
if (usRet != 0)
|
|
return usRet;
|
|
|
|
/*
|
|
* Fill in the loadseg, refcount, and name entries in the handle.
|
|
*/
|
|
|
|
pModuleHandle->usModuleLoadSeg = usLoadSeg;
|
|
pModuleHandle->RefCount = 1;
|
|
strcpy(pModuleHandle->ModuleName, BaseName);
|
|
|
|
/*
|
|
* Set a function pointer to point at the entry point. This function
|
|
* should be of the form:
|
|
* unsigned short DOSDLLInit( struct FunctionTable *pFT );
|
|
*
|
|
* and should set the parameter pointing at this DLLs function table
|
|
* The return code should be 0 if successful and non-zero
|
|
* if an init error occurred.
|
|
*/
|
|
|
|
FP_OFF(pfnDLLInit) = ExeHdr.usIPContentAtStartup;
|
|
FP_SEG(pfnDLLInit) = usLoadSeg+ExeHdr.usCodeSegDisplacement;
|
|
|
|
usRet = (*pfnDLLInit)( &(pModuleHandle->pFunctionTable) );
|
|
if (usRet != 0)
|
|
{
|
|
usLoadSeg -= PARAGRAPH_SIZE(struct ModuleHandle);
|
|
_dos_freemem(usLoadSeg);
|
|
return usRet;
|
|
}
|
|
|
|
/*
|
|
* Add new module handle to list.
|
|
*/
|
|
|
|
pModuleHandle->pNext = LoadedModuleList;
|
|
LoadedModuleList = pModuleHandle;
|
|
}
|
|
|
|
/*
|
|
* Fill in user handle.
|
|
*/
|
|
|
|
*pulHandle = (unsigned long)pModuleHandle;
|
|
|
|
/*
|
|
* Return successfully.
|
|
*/
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
PFN DLL_ENTRY
|
|
GetProcAddress(
|
|
HINSTANCE Handle,
|
|
char * Name
|
|
)
|
|
{
|
|
PFN Fn;
|
|
|
|
if (GetProcAddrR(Handle, Name, &Fn))
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return Fn;
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
*
|
|
* Name: GetProcAddrR
|
|
*
|
|
* Purpose: Retrieves the address of a named function in a loaded DLL.
|
|
*
|
|
\*****************************************************************************/
|
|
|
|
unsigned short DLL_ENTRY
|
|
GetProcAddrR( HINSTANCE ulHandle,
|
|
char * pszProcName,
|
|
PPFN ppfnFunctionAddr )
|
|
{
|
|
struct FunctionTable * pFT;
|
|
|
|
|
|
/*
|
|
* Search the function table at the start of the DLL for the one
|
|
* specified in the call. Note that the search is case-INsensitive.
|
|
* (ulHandle is actually a pointer to the start of the DLL).
|
|
*/
|
|
|
|
pFT = ((struct ModuleHandle *)ulHandle)->pFunctionTable;
|
|
|
|
while (pFT->pszFunctionName != NULL)
|
|
{
|
|
if (_stricmp( pszProcName, pFT->pszFunctionName) == 0)
|
|
{
|
|
*ppfnFunctionAddr = pFT->pfnFunction;
|
|
return 0;
|
|
}
|
|
pFT++;
|
|
}
|
|
|
|
return ERROR_PROC_NOT_FOUND;
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
*
|
|
* Name: UnLoadModR
|
|
*
|
|
* Purpose: Unloads a DLL and frees up the memory it is occupying.
|
|
*
|
|
\*****************************************************************************/
|
|
|
|
|
|
|
|
unsigned short DLL_ENTRY
|
|
UnloadModR( HINSTANCE ulHandle )
|
|
{
|
|
unsigned short segment;
|
|
struct ModuleHandle * pModule = (struct ModuleHandle *) ulHandle;
|
|
|
|
--pModule->RefCount;
|
|
|
|
if (0 == pModule->RefCount)
|
|
{
|
|
if (pModule == LoadedModuleList)
|
|
{
|
|
LoadedModuleList = pModule->pNext;
|
|
}
|
|
else
|
|
{
|
|
struct ModuleHandle * pNode = LoadedModuleList;
|
|
while (pNode)
|
|
{
|
|
if (pNode->pNext == pModule)
|
|
{
|
|
pNode->pNext = pModule->pNext;
|
|
break;
|
|
}
|
|
pNode = pNode->pNext;
|
|
}
|
|
}
|
|
|
|
segment = FP_SEG(pModule);
|
|
_dos_freemem( segment );
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
HINSTANCE DLL_ENTRY
|
|
GetModuleHandle(
|
|
char * Name
|
|
)
|
|
{
|
|
char FullFileName[8+1+3+1];
|
|
|
|
strcpy(FullFileName, FindBaseName(Name));
|
|
|
|
return (unsigned long) _FindModuleHandle(FullFileName);
|
|
}
|
|
|
|
|
|
char *
|
|
FindBaseName(
|
|
char * PathName
|
|
)
|
|
{
|
|
char * PathIndex = strrchr(PathName, '\\');
|
|
|
|
if (PathIndex)
|
|
{
|
|
return PathIndex+1;
|
|
}
|
|
else
|
|
{
|
|
return PathName;
|
|
}
|
|
}
|
|
|
|
|
|
struct ModuleHandle *
|
|
_FindModuleHandle(
|
|
char * ModuleName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a module name, the fn finds the module in the list of loaded modules.
|
|
|
|
Arguments:
|
|
|
|
ModuleName - module name. extension is optional but paths are not allowed
|
|
|
|
Return Value:
|
|
|
|
a pointer to the module handle if successful
|
|
0 if not loaded
|
|
|
|
Exceptions:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
struct ModuleHandle * pModule;
|
|
char * DotIndex = strrchr(ModuleName, '.');
|
|
|
|
/*
|
|
* If the last period follows the last path separator, the module name
|
|
* has no extension. Add ".dll".
|
|
*/
|
|
|
|
if (!DotIndex)
|
|
{
|
|
strcat(ModuleName, DllDefaultExtension);
|
|
}
|
|
|
|
for (pModule = LoadedModuleList; pModule; pModule = pModule->pNext)
|
|
{
|
|
if (0 == _stricmp(pModule->ModuleName, ModuleName))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return pModule;
|
|
}
|