windows-nt/Source/XPSP1/NT/multimedia/directx/dinput/dx8/dll/dithunk.c
2020-09-26 16:20:57 +08:00

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;
}