468 lines
12 KiB
C
468 lines
12 KiB
C
|
/*****************************************************************************
|
||
|
*
|
||
|
* DiThunk.c
|
||
|
*
|
||
|
* Copyright (c) 1996-1997 Microsoft Corporation. All Rights Reserved.
|
||
|
*
|
||
|
* Abstract:
|
||
|
*
|
||
|
* Template thunks for Windows 95 device manager.
|
||
|
*
|
||
|
* Contents:
|
||
|
*
|
||
|
* Thunk_Init
|
||
|
* Thunk_Term
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
#include "dinputpr.h"
|
||
|
#include "dithunk.h"
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* The sqiffle for this file.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
#define sqfl sqflThunk
|
||
|
|
||
|
|
||
|
KERNELPROCADDR g_kpa;
|
||
|
|
||
|
#pragma BEGIN_CONST_DATA
|
||
|
|
||
|
/*
|
||
|
* Careful! This must match KERNELPROCADDR ...
|
||
|
*/
|
||
|
static LPCSTR c_rgpszKernel32[] = {
|
||
|
(LPVOID) 35, /* LoadLibrary16 */
|
||
|
(LPVOID) 36, /* FreeLibrary16 */
|
||
|
(LPVOID) 37, /* GetProcAddress16 */
|
||
|
|
||
|
"MapLS",
|
||
|
"UnMapLS",
|
||
|
"MapSL",
|
||
|
"MapSLFix",
|
||
|
"UnMapSLFixArray",
|
||
|
"QT_Thunk",
|
||
|
};
|
||
|
|
||
|
/***************************************************************************
|
||
|
*
|
||
|
* @doc INTERNAL
|
||
|
*
|
||
|
* @func DWORD | TemplateThunk |
|
||
|
*
|
||
|
* Call down, passing all sorts of random parameters.
|
||
|
*
|
||
|
* Parameter signature is as follows:
|
||
|
*
|
||
|
* p = 0:32 pointer to convert to 16:16 pointer
|
||
|
*
|
||
|
* l = a 32-bit integer
|
||
|
*
|
||
|
* s = a 16-bit integer
|
||
|
*
|
||
|
*
|
||
|
* P = returns a pointer
|
||
|
*
|
||
|
* L = returns a 32-bit integer
|
||
|
*
|
||
|
* S = returns a 16-bit signed integer
|
||
|
*
|
||
|
* U = returns a 16-bit unsigned integer
|
||
|
*
|
||
|
***************************************************************************/
|
||
|
|
||
|
#pragma warning(disable:4035) /* no return value (duh) */
|
||
|
|
||
|
#ifdef WIN95
|
||
|
#ifdef SLOW_BUT_READABLE
|
||
|
|
||
|
__declspec(naked) int
|
||
|
TemplateThunk(FARPROC fp, PCSTR pszSig, ...)
|
||
|
{
|
||
|
BYTE rgbThunk[60]; /* For private use of QT_Thunk */
|
||
|
LPVOID *ppvArg;
|
||
|
int i;
|
||
|
LPVOID pv;
|
||
|
int iRc;
|
||
|
|
||
|
__asm {
|
||
|
|
||
|
/* Function prologue */
|
||
|
push ebp;
|
||
|
mov ebp, esp;
|
||
|
sub esp, __LOCAL_SIZE;
|
||
|
push ebx;
|
||
|
push edi;
|
||
|
push esi;
|
||
|
|
||
|
}
|
||
|
|
||
|
/* Thunk all the parameters according to the signature */
|
||
|
ppvArg = (LPVOID)(&pszSig+1);
|
||
|
for (i = 0; ; i++) {
|
||
|
pv = ppvArg[i];
|
||
|
switch (pszSig[i]) {
|
||
|
case 'p':
|
||
|
pv = ppvArg[i] = MapLS(pv);
|
||
|
__asm push pv;
|
||
|
break;
|
||
|
|
||
|
case 'l':
|
||
|
__asm push pv;
|
||
|
break;
|
||
|
|
||
|
case 's':
|
||
|
__asm mov eax, pv;
|
||
|
__asm push ax;
|
||
|
break;
|
||
|
|
||
|
default: goto doneThunk;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
doneThunk:;
|
||
|
|
||
|
/* Call the 16:16 procedure */
|
||
|
__asm {
|
||
|
mov edx, fp;
|
||
|
mov ebx, ebp;
|
||
|
lea ebp, rgbThunk+64; /* Required by QT_Thunk */
|
||
|
}
|
||
|
g_kpa.QT_Thunk();
|
||
|
__asm {
|
||
|
mov ebp, ebx;
|
||
|
shl eax, 16; /* Convert DX:AX to EAX */
|
||
|
shrd eax, edx, 16;
|
||
|
mov iRc, eax;
|
||
|
}
|
||
|
|
||
|
/* Now unthunk the parameters */
|
||
|
ppvArg = (LPVOID)(&pszSig+1);
|
||
|
for (i = 0; ; i++) {
|
||
|
switch (pszSig[i]) {
|
||
|
case 'p':
|
||
|
UnMapLS(ppvArg[i]);
|
||
|
break;
|
||
|
|
||
|
case 'l':
|
||
|
case 's':
|
||
|
break;
|
||
|
|
||
|
default: goto doneUnthunk;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
doneUnthunk:;
|
||
|
|
||
|
/* Thunk the return value */
|
||
|
switch (pszSig[i]) {
|
||
|
case 'L':
|
||
|
break;
|
||
|
|
||
|
case 'U':
|
||
|
iRc = LOWORD(iRc);
|
||
|
break;
|
||
|
|
||
|
case 'S':
|
||
|
iRc = (short)iRc;
|
||
|
break;
|
||
|
|
||
|
case 'P':
|
||
|
iRc = (int)MapSL((LPVOID)iRc);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
__asm {
|
||
|
mov eax, iRc;
|
||
|
pop esi;
|
||
|
pop edi;
|
||
|
pop ebx;
|
||
|
mov esp, ebp;
|
||
|
pop ebp;
|
||
|
ret;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#else /* Fast but illegible */
|
||
|
|
||
|
__declspec(naked) int
|
||
|
TemplateThunk(FARPROC fp, PCSTR pszSig, ...)
|
||
|
{
|
||
|
__asm {
|
||
|
|
||
|
/* Function prologue */
|
||
|
push ebp;
|
||
|
mov ebp, esp;
|
||
|
sub esp, 60; /* QT_Thunk needs 60 bytes */
|
||
|
push ebx;
|
||
|
push edi;
|
||
|
push esi;
|
||
|
|
||
|
/* Thunk all the parameters according to the signature */
|
||
|
|
||
|
lea esi, pszSig+4; /* esi -> next arg */
|
||
|
mov ebx, pszSig; /* ebx -> signature string */
|
||
|
thunkLoop:;
|
||
|
mov al, [ebx];
|
||
|
inc ebx; /* al = pszSig++ */
|
||
|
cmp al, 'p'; /* Q: Pointer? */
|
||
|
jz thunkPtr; /* Y: Do the pointer */
|
||
|
cmp al, 'l'; /* Q: Long? */
|
||
|
jz thunkLong; /* Y: Do the long */
|
||
|
cmp al, 's'; /* Q: Short? */
|
||
|
jnz thunkDone; /* N: Done */
|
||
|
|
||
|
/* Y: Do the short */
|
||
|
lodsd; /* eax = *ppvArg++ */
|
||
|
push ax; /* Push the short */
|
||
|
jmp thunkLoop;
|
||
|
|
||
|
thunkPtr:
|
||
|
lodsd; /* eax = *ppvArg++ */
|
||
|
push eax;
|
||
|
call dword ptr g_kpa.MapLS; /* Map it */
|
||
|
mov [esi][-4], eax; /* Save it for unmapping */
|
||
|
push eax;
|
||
|
jmp thunkLoop;
|
||
|
|
||
|
thunkLong:
|
||
|
lodsd; /* eax = *ppvArg++ */
|
||
|
push eax;
|
||
|
jmp thunkLoop;
|
||
|
thunkDone:
|
||
|
|
||
|
/* Call the 16:16 procedure */
|
||
|
|
||
|
mov edx, fp;
|
||
|
call dword ptr g_kpa.QT_Thunk;
|
||
|
shl eax, 16; /* Convert DX:AX to EDX */
|
||
|
shld edx, eax, 16;
|
||
|
|
||
|
/* Translate the return code according to the signature */
|
||
|
|
||
|
mov al, [ebx][-1]; /* Get return code type */
|
||
|
cmp al, 'P'; /* Pointer? */
|
||
|
jz retvalPtr; /* Y: Do the pointer */
|
||
|
cmp al, 'S'; /* Signed? */
|
||
|
jz retvalSigned; /* Y: Do the signed short */
|
||
|
cmp al, 'U'; /* Unsigned? */
|
||
|
mov edi, edx; /* Assume long or void */
|
||
|
jnz retvalOk; /* N: Then long or void */
|
||
|
|
||
|
movzx edi, dx; /* Sign-extend short */
|
||
|
jmp retvalOk;
|
||
|
|
||
|
retvalPtr:
|
||
|
push edx; /* Pointer */
|
||
|
call dword ptr g_kpa.MapSL; /* Map it up */
|
||
|
jmp retvalOk;
|
||
|
|
||
|
retvalSigned: /* Signed */
|
||
|
movsx edi, dx; /* Sign-extend short */
|
||
|
jmp retvalOk;
|
||
|
|
||
|
retvalOk: /* Return value in EDI */
|
||
|
|
||
|
/* Now unthunk the parameters */
|
||
|
|
||
|
lea esi, pszSig+4; /* esi -> next arg */
|
||
|
mov ebx, pszSig; /* ebx -> signature string */
|
||
|
unthunkLoop:;
|
||
|
mov al, [ebx];
|
||
|
inc ebx; /* al = pszSig++ */
|
||
|
cmp al, 'p'; /* Pointer? */
|
||
|
jz unthunkPtr; /* Y: Do the pointer */
|
||
|
cmp al, 'l'; /* Long? */
|
||
|
jz unthunkSkip; /* Y: Skip it */
|
||
|
cmp al, 's'; /* Short? */
|
||
|
jnz unthunkDone; /* N: Done */
|
||
|
unthunkSkip:
|
||
|
lodsd; /* eax = *ppvArg++ */
|
||
|
jmp unthunkLoop;
|
||
|
|
||
|
unthunkPtr:
|
||
|
lodsd; /* eax = *ppvArg++ */
|
||
|
push eax;
|
||
|
call dword ptr g_kpa.UnMapLS;/* Unmap it */
|
||
|
jmp unthunkLoop;
|
||
|
|
||
|
unthunkDone:
|
||
|
|
||
|
/* Done */
|
||
|
|
||
|
mov eax, edi;
|
||
|
pop esi;
|
||
|
pop edi;
|
||
|
pop ebx;
|
||
|
mov esp, ebp;
|
||
|
pop ebp;
|
||
|
ret;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#else // Not X86
|
||
|
int __cdecl TemplateThunk(FARPROC fp, PCSTR pszSig, ...)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#pragma BEGIN_CONST_DATA
|
||
|
|
||
|
/***************************************************************************
|
||
|
*
|
||
|
* @doc INTERNAL
|
||
|
*
|
||
|
* @func FARPROC | GetProcOrd |
|
||
|
*
|
||
|
* GetProcAddress on a DLL by ordinal.
|
||
|
*
|
||
|
* Win95 does not let you GetProcAddress on KERNEL32 by ordinal,
|
||
|
* so we need to do it the evil way.
|
||
|
*
|
||
|
* @parm HINSTANCE | hinstDll |
|
||
|
*
|
||
|
* The instance handle of the DLL we want to get the ordinal
|
||
|
* from. The only DLL you need to use this function for is
|
||
|
* KERNEL32.
|
||
|
*
|
||
|
* @parm UINT | ord |
|
||
|
*
|
||
|
* The ordinal you want to retrieve.
|
||
|
*
|
||
|
***************************************************************************/
|
||
|
|
||
|
#define poteExp(pinth) (&(pinth)->OptionalHeader. \
|
||
|
DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT])
|
||
|
|
||
|
FARPROC NTAPI
|
||
|
GetProcOrd(HINSTANCE hinstDll, UINT ord)
|
||
|
{
|
||
|
FARPROC fp;
|
||
|
|
||
|
/*
|
||
|
* Make sure the MZ header is good.
|
||
|
*/
|
||
|
|
||
|
PIMAGE_DOS_HEADER pidh = (LPVOID)hinstDll;
|
||
|
if (!IsBadReadPtr(pidh, sizeof(*pidh)) &&
|
||
|
pidh->e_magic == IMAGE_DOS_SIGNATURE) {
|
||
|
|
||
|
/*
|
||
|
* Make sure the PE header is good.
|
||
|
*/
|
||
|
PIMAGE_NT_HEADERS pinth = pvAddPvCb(pidh, pidh->e_lfanew);
|
||
|
if (!IsBadReadPtr(pinth, sizeof(*pinth)) &&
|
||
|
pinth->Signature == IMAGE_NT_SIGNATURE) {
|
||
|
|
||
|
/*
|
||
|
* Make sure the export table is good and the ordinal
|
||
|
* is within range.
|
||
|
*/
|
||
|
PIMAGE_EXPORT_DIRECTORY pedt =
|
||
|
pvAddPvCb(pidh, poteExp(pinth)->VirtualAddress);
|
||
|
if (!IsBadReadPtr(pedt, sizeof(*pedt)) &&
|
||
|
(ord - pedt->Base) < pedt->NumberOfFunctions) {
|
||
|
|
||
|
PDWORD peat = pvAddPvCb(pidh, (DWORD)pedt->AddressOfFunctions);
|
||
|
fp = (FARPROC)pvAddPvCb(pidh, peat[ord - pedt->Base]);
|
||
|
if ((DWORD)cbSubPvPv(fp, peat) >= poteExp(pinth)->Size) {
|
||
|
/* fp is valid */
|
||
|
} else { /* Note: We don't support forwarding */
|
||
|
fp = 0;
|
||
|
}
|
||
|
} else {
|
||
|
fp = 0;
|
||
|
}
|
||
|
} else {
|
||
|
fp = 0;
|
||
|
}
|
||
|
} else {
|
||
|
fp = 0;
|
||
|
}
|
||
|
|
||
|
return fp;
|
||
|
}
|
||
|
|
||
|
/***************************************************************************
|
||
|
*
|
||
|
* @doc INTERNAL
|
||
|
*
|
||
|
* @func BOOL | GetKernelProcAddresses |
|
||
|
*
|
||
|
* Get all the necessary proc addresses from Kernel.
|
||
|
*
|
||
|
***************************************************************************/
|
||
|
|
||
|
BOOL EXTERNAL
|
||
|
Thunk_GetKernelProcAddresses(void)
|
||
|
{
|
||
|
DllEnterCrit();
|
||
|
|
||
|
if (g_kpa.QT_Thunk == 0) {
|
||
|
HINSTANCE hinstK32 = GetModuleHandle(TEXT("KERNEL32"));
|
||
|
|
||
|
if (hinstK32) {
|
||
|
int i;
|
||
|
FARPROC *rgfpKpa = (LPVOID)&g_kpa;
|
||
|
|
||
|
for (i = 0; i < cA(c_rgpszKernel32); i++) {
|
||
|
if (HIWORD((UINT_PTR)c_rgpszKernel32[i])) {
|
||
|
rgfpKpa[i] = GetProcAddress(hinstK32, c_rgpszKernel32[i]);
|
||
|
} else {
|
||
|
rgfpKpa[i] = GetProcOrd(hinstK32, (UINT)(UINT_PTR)c_rgpszKernel32[i]);
|
||
|
}
|
||
|
if (!rgfpKpa[i]) break; /* Aigh! */
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DllLeaveCrit();
|
||
|
|
||
|
return (BOOL)(UINT_PTR)g_kpa.QT_Thunk;
|
||
|
|
||
|
}
|
||
|
|
||
|
/***************************************************************************
|
||
|
*
|
||
|
* @doc INTERNAL
|
||
|
*
|
||
|
* @func HINSTANCE | ThunkGetProcAddresses |
|
||
|
*
|
||
|
* Get all the necessary proc addresses.
|
||
|
*
|
||
|
***************************************************************************/
|
||
|
|
||
|
HINSTANCE EXTERNAL
|
||
|
Thunk_GetProcAddresses(FARPROC *rgfp, LPCSTR *rgpsz,
|
||
|
UINT cfp, LPCSTR pszLibrary)
|
||
|
{
|
||
|
HINSTANCE hinst;
|
||
|
|
||
|
hinst = g_kpa.LoadLibrary16(pszLibrary);
|
||
|
if (hinst >= (HINSTANCE)32) {
|
||
|
UINT ifp;
|
||
|
for (ifp = 0; ifp < cfp; ifp++) {
|
||
|
rgfp[ifp] = g_kpa.GetProcAddress16(hinst, rgpsz[ifp]);
|
||
|
if (!rgfp[ifp]) {
|
||
|
g_kpa.FreeLibrary16(hinst);
|
||
|
hinst = 0;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
hinst = 0;
|
||
|
}
|
||
|
|
||
|
return hinst;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|