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.
510 lines
13 KiB
510 lines
13 KiB
/********************************************************************
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
thunk.c
|
|
|
|
Abstract:
|
|
Thunk procedures for calling 16-bit functions
|
|
|
|
Revision History:
|
|
|
|
Brijesh Krishnaswami (brijeshk) 05/24/99
|
|
- created (imported from msinfo codebase)
|
|
********************************************************************/
|
|
|
|
#include <windows.h>
|
|
#include "drvdefs.h"
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* @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
|
|
|
|
__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
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#pragma warning(default:4035)
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* Functions we call down in Win16.
|
|
*
|
|
***************************************************************************/
|
|
|
|
FARPROC g_rgfpKernel[] = {
|
|
(FARPROC)132, /* GetWinFlags */
|
|
(FARPROC)355, /* GetWinDebugInfo */
|
|
(FARPROC)169, /* GetFreeSpace */
|
|
(FARPROC) 47, /* GetModuleHandle */
|
|
(FARPROC) 93, /* GetCodeHandle */
|
|
(FARPROC)104, /* GetCodeInfo */
|
|
(FARPROC) 49, /* GetModuleFileName */
|
|
(FARPROC)175, /* AllocSelector */
|
|
(FARPROC)186, /* GetSelectorBase */
|
|
(FARPROC)187, /* SetSelectorBase */
|
|
(FARPROC)188, /* GetSelectorLimit */
|
|
(FARPROC)189, /* SetSelectorLimit */
|
|
(FARPROC)176, /* FreeSelector */
|
|
(FARPROC) 27, /* GetModuleName */
|
|
(FARPROC)167, /* GetExpWinVer */
|
|
(FARPROC)184, /* GlobalDosAlloc */
|
|
(FARPROC)185, /* GlobalDosFree */
|
|
(FARPROC) 16, /* GlobalReAlloc */
|
|
};
|
|
|
|
|
|
#define g_fpGetWinFlags g_rgfpKernel[0]
|
|
#define g_fpGetWinDebugInfo g_rgfpKernel[1]
|
|
#define g_fpGetFreeSpace g_rgfpKernel[2]
|
|
#define g_fpGetModuleHandle g_rgfpKernel[3]
|
|
#define g_fpGetCodeHandle g_rgfpKernel[4]
|
|
#define g_fpGetCodeInfo g_rgfpKernel[5]
|
|
#define g_fpGetModuleFileName g_rgfpKernel[6]
|
|
#define g_fpAllocSelector g_rgfpKernel[7]
|
|
#define g_fpGetSelectorBase g_rgfpKernel[8]
|
|
#define g_fpSetSelectorBase g_rgfpKernel[9]
|
|
#define g_fpGetSelectorLimit g_rgfpKernel[10]
|
|
#define g_fpSetSelectorLimit g_rgfpKernel[11]
|
|
#define g_fpFreeSelector g_rgfpKernel[12]
|
|
#define g_fpGetModuleName g_rgfpKernel[13]
|
|
#define g_fpGetExpWinVer g_rgfpKernel[14]
|
|
#define g_fpGlobalDosAlloc g_rgfpKernel[15]
|
|
#define g_fpGlobalDosFree g_rgfpKernel[16]
|
|
#define g_fpGlobalReAlloc g_rgfpKernel[17]
|
|
|
|
|
|
FARPROC g_rgfpUser[] = {
|
|
(FARPROC)216, /* UserSeeUserDo */
|
|
(FARPROC)284, /* GetFreeSystemResources */
|
|
(FARPROC)256, /* GetDriverInfo */
|
|
(FARPROC)257, /* GetNextDriver */
|
|
};
|
|
|
|
#define g_fpUserSeeUserDo g_rgfpUser[0]
|
|
#define g_fpGetFreeSystemResources g_rgfpUser[1]
|
|
#define g_fpGetDriverInfo g_rgfpUser[2]
|
|
#define g_fpGetNextDriver g_rgfpUser[3]
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* @doc INTERNAL
|
|
*
|
|
* @func void | ThunkGetProcAddresses |
|
|
*
|
|
* Get all the necessary proc addresses.
|
|
*
|
|
***************************************************************************/
|
|
|
|
HINSTANCE
|
|
ThunkGetProcAddresses(FARPROC *rgfp, UINT cfp, LPCTSTR ptszLibrary,
|
|
BOOL fFree)
|
|
{
|
|
HINSTANCE hinst;
|
|
|
|
hinst = LoadLibrary16(ptszLibrary);
|
|
if (hinst >= (HINSTANCE)32) {
|
|
UINT ifp;
|
|
for (ifp = 0; ifp < cfp; ifp++) {
|
|
rgfp[ifp] = GetProcAddress16(hinst, (PVOID)rgfp[ifp]);
|
|
}
|
|
|
|
if (fFree) {
|
|
FreeLibrary16(hinst);
|
|
}
|
|
|
|
} else {
|
|
hinst = 0;
|
|
}
|
|
|
|
return hinst;
|
|
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
* @doc INTERNAL
|
|
*
|
|
* @func void | ThunkInit |
|
|
*
|
|
* GetProcAddress16 our brains out.
|
|
*
|
|
***************************************************************************/
|
|
|
|
LPVOID g_pvWin16Lock = NULL;
|
|
HINSTANCE g_hinstUser;
|
|
|
|
void
|
|
ThunkInit(void)
|
|
{
|
|
if (g_pvWin16Lock == NULL)
|
|
{
|
|
ThunkGetProcAddresses(g_rgfpKernel, cA(g_rgfpKernel), TEXT("KERNEL"), 1);
|
|
g_hinstUser = ThunkGetProcAddresses(g_rgfpUser, cA(g_rgfpUser), TEXT("USER"), 1);
|
|
GetpWin16Lock(&g_pvWin16Lock);
|
|
}
|
|
}
|
|
|
|
|
|
HMODULE16
|
|
GetModuleHandle16(LPCSTR pszModule)
|
|
{
|
|
return (HMODULE16)TemplateThunk(g_fpGetModuleHandle, "pU", pszModule);
|
|
}
|
|
|
|
int
|
|
GetModuleFileName16(HMODULE16 hmod, LPSTR sz, int cch)
|
|
{
|
|
return TemplateThunk(g_fpGetModuleFileName, "spsS", hmod, sz, cch);
|
|
}
|
|
|
|
int
|
|
GetModuleName16(HMODULE16 hmod, LPSTR sz, int cch)
|
|
{
|
|
return TemplateThunk(g_fpGetModuleName, "spsS", hmod, sz, cch);
|
|
}
|
|
|
|
UINT
|
|
AllocCodeSelector16(void)
|
|
{
|
|
return TemplateThunk(g_fpAllocSelector, "sU", HIWORD(g_fpAllocSelector));
|
|
}
|
|
|
|
|
|
DWORD
|
|
GetSelectorBase16(UINT sel)
|
|
{
|
|
return TemplateThunk(g_fpGetSelectorBase, "sL", sel);
|
|
}
|
|
|
|
|
|
UINT
|
|
SetSelectorBase16(UINT sel, DWORD dwBase)
|
|
{
|
|
return TemplateThunk(g_fpSetSelectorBase, "slU", sel, dwBase);
|
|
}
|
|
|
|
|
|
DWORD
|
|
GetSelectorLimit16(UINT sel)
|
|
{
|
|
return TemplateThunk(g_fpGetSelectorLimit, "sL", sel);
|
|
}
|
|
|
|
|
|
UINT
|
|
SetSelectorLimit16(UINT sel, DWORD dwLimit)
|
|
{
|
|
return TemplateThunk(g_fpSetSelectorLimit, "slU", sel, dwLimit);
|
|
}
|
|
|
|
UINT
|
|
FreeSelector16(UINT sel)
|
|
{
|
|
return TemplateThunk(g_fpFreeSelector, "sU", sel);
|
|
}
|
|
|
|
WORD
|
|
GetExpWinVer16(HMODULE16 hmod)
|
|
{
|
|
return (WORD)TemplateThunk(g_fpGetExpWinVer, "sS", hmod);
|
|
}
|
|
|
|
DWORD
|
|
GlobalDosAlloc16(DWORD cb)
|
|
{
|
|
return (DWORD)TemplateThunk(g_fpGlobalDosAlloc, "lL", cb);
|
|
}
|
|
|
|
UINT
|
|
GlobalDosFree16(UINT uiSel)
|
|
{
|
|
return (UINT)TemplateThunk(g_fpGlobalDosFree, "sS", uiSel);
|
|
}
|
|
|
|
/*
|
|
* Kernel has thunks for GlobalAlloc, GlobalFree, but not GlobalRealloc.
|
|
*/
|
|
WORD
|
|
GlobalReAlloc16(WORD hglob, DWORD cb, UINT fl)
|
|
{
|
|
return (WORD)TemplateThunk(g_fpGlobalReAlloc, "slsS", hglob, cb, fl);
|
|
}
|
|
|
|
#define SD_ATOMNAME 0x000E
|
|
|
|
UINT
|
|
GetUserAtomName(UINT atom, LPSTR psz)
|
|
{
|
|
return (UINT)TemplateThunk(g_fpUserSeeUserDo, "sspS",
|
|
SD_ATOMNAME, atom, psz);
|
|
}
|
|
|
|
#define SD_GETRGPHKSYSHOOKS 0x0010
|
|
|
|
DWORD
|
|
GetUserHookTable(void)
|
|
{
|
|
return (UINT)TemplateThunk(g_fpUserSeeUserDo, "sslL",
|
|
SD_GETRGPHKSYSHOOKS, 0, 0);
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetDriverInfo16(WORD hDriver, DRIVERINFOSTRUCT16* pdis)
|
|
{
|
|
return (BOOL)TemplateThunk(g_fpGetDriverInfo, "spS", hDriver, pdis);
|
|
}
|
|
|
|
WORD
|
|
GetNextDriver16(WORD hDriver, DWORD fdwFlag)
|
|
{
|
|
return (WORD)TemplateThunk(g_fpGetNextDriver, "slS", hDriver, fdwFlag);
|
|
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* @doc INTERNAL
|
|
*
|
|
* @func BOOL | Int86x |
|
|
*
|
|
* Issue a real-mode software interrupt.
|
|
*
|
|
* We do this by allocating a temporary code selector and
|
|
* thunking to it.
|
|
*
|
|
*
|
|
***************************************************************************/
|
|
|
|
BYTE rgbInt31[] = {
|
|
0x55, /* push bp */
|
|
0x8B, 0xEC, /* mov bp, sp */
|
|
0x57, /* push di */
|
|
0xC4, 0x7E, 0x06, /* les di, [bp+6] */
|
|
0x8B, 0x5E, 0x0A, /* mov bx, [bp+10] */
|
|
0x33, 0xC9, /* xor cx, cx */
|
|
0xB8, 0x00, 0x03, /* mov ax, 0300h */
|
|
0xCD, 0x31, /* int 31h */
|
|
0x72, 0x02, /* jc $+4 */
|
|
0x33, 0xC0, /* xor ax, ax */
|
|
0x5F, /* pop di */
|
|
0x5D, /* pop bp */
|
|
0xCA, 0x06, 0x00, /* retf 6 */
|
|
};
|
|
|
|
UINT
|
|
Int86x(UINT intno, PRMIREGS preg)
|
|
{
|
|
UINT selCode = AllocCodeSelector16();
|
|
UINT uiRc;
|
|
if (selCode) {
|
|
SetSelectorBase16(selCode, (DWORD)rgbInt31);
|
|
SetSelectorLimit16(selCode, sizeof(rgbInt31));
|
|
preg->ss = preg->sp = 0;
|
|
uiRc = (UINT)TemplateThunk((FARPROC)MAKELONG(0, selCode),
|
|
"spU", intno, preg);
|
|
FreeSelector16(selCode);
|
|
} else {
|
|
uiRc = 0x8011; /* Descriptor unavailable */
|
|
}
|
|
return uiRc;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* @doc INTERNAL : ported from msinfo 4.10 code
|
|
*
|
|
* @func Token_Find |
|
|
*
|
|
* Returns the first token in the string.
|
|
*
|
|
* Tokens are space or comma separated strings. Quotation marks
|
|
* have no effect. We also treat semicolons as separators.
|
|
* (This lets us use this routine for walking the PATH too.)
|
|
*
|
|
* *pptsz is modified in place to contain a pointer that can
|
|
* be passed subsequently to Token_Find to pull the next token.
|
|
*
|
|
***************************************************************************/
|
|
LPTSTR Token_Find(LPTSTR *pptsz)
|
|
{
|
|
LPTSTR ptsz = *pptsz;
|
|
while (*ptsz) {
|
|
|
|
/*
|
|
* Skip leading separators.
|
|
*/
|
|
while (*ptsz == TEXT(' ') ||
|
|
*ptsz == TEXT(',') ||
|
|
*ptsz == TEXT(';')) {
|
|
ptsz++;
|
|
}
|
|
|
|
if (*ptsz) {
|
|
LPTSTR ptszStart = ptsz;
|
|
|
|
/*
|
|
* Skip until we see a separator.
|
|
*/
|
|
while (*ptsz != TEXT('\0') &&
|
|
*ptsz != TEXT(' ') &&
|
|
*ptsz != TEXT(',') &&
|
|
*ptsz != TEXT(';')) {
|
|
ptsz++;
|
|
}
|
|
|
|
/*
|
|
* Wipe out the separator, and advance ptsz past it
|
|
* if there is something after it. (Don't advance
|
|
* it beyond the end of the string!)
|
|
*/
|
|
if (*ptsz) {
|
|
*ptsz++ = 0;
|
|
}
|
|
*pptsz = ptsz;
|
|
|
|
return ptszStart;
|
|
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
#pragma warning(default:4035)
|
|
|
|
|
|
|