home *** CD-ROM | disk | FTP | other *** search
- /*
- HANDLES.C -- KERNEL-related handles
- from "Undocumented Windows" by Schulman et al. (Addison-Wesley, 1992)
- Chapter 5: KERNEL
- Copyright (c) Andrew Schulman and Matt Pietrek 1992
- */
-
- #include <dos.h>
- #include "windows.h"
- #include "handles.h"
-
- extern DWORD FAR PASCAL GetSelectorBase(WORD wSel);
- extern DWORD FAR PASCAL GetSelectorLimit(WORD wSel);
- extern WORD FAR PASCAL SetSelectorBase(WORD wSel, DWORD dwBase);
- extern WORD FAR PASCAL SetSelectorLimit(WORD wSel, DWORD dwLimit);
-
- /* Convert a handle to a selector, just the way TOOLHELP
- does. See WINMOD.C for explanation */
- WORD HandleToSel(HANDLE h)
- {
- static WORD wVers = 0;
- if (! wVers) // one-time initialization
- wVers = (WORD) GetVersion();
- if (wVers == 3) // 3.0: handles = selectors+1
- return ((h & 2) == 2) ? h-1 : h;
- else // 3.1++: handles = selectors-1
- return (h | 1);
- }
-
- /* Turn hInstance into hTask: walk the task list (see sample
- code in the entries for GetCurrentTask() and the Task Database),
- searching for a TDB whose WORD at offset 1Ch matches the hInstance,
- i.e., where HINSTANCE_FROM_HTASK(hTask) == hInstance */
- WORD hTask_from_hInstance(WORD hInstance)
- {
- DWORD (FAR PASCAL *GetCurrentTaskD)(void) = GetCurrentTask;
- DWORD dwTask = GetCurrentTaskD();
- HANDLE hTask = HIWORD(dwTask); // get base of linked list
- for (;;)
- {
- if (HINSTANCE_FROM_HTASK(hTask) == hInstance)
- return hTask;
-
- /* Get the handle of the next task from offset 0 in the Task DB */
- if ((hTask = *((WORD far *) MK_FP(hTask, 0))) == 0)
- break;
- }
- /* still here -- didn't find it */
- return 0;
- }
-
- /* Turn PDB (PSP) into hTask: this is for the truly masochistic. Use
- GetSelectorBase() to obtain the linear address of the PSP. Subtract
- 100h, and create a new selector with the resulting base address. This
- new selector points at the TDB, and the hTask can be found at offset
- 0Ch. It would be wise to "sanity check" by making sure that the WORD
- at offset 0FAh is 'TD' */
- HANDLE hTask_from_PSP(WORD wPSP)
- {
- WORD hTask, hMyTask, wDS;
- _asm mov wDS, ds
- hMyTask = AllocSelector(wDS); // use DS as model
- SetSelectorBase(hMyTask, GetSelectorBase(wPSP) - 0x100);
- SetSelectorLimit(hMyTask, 0x100);
- if (*((WORD far *) MK_FP(hMyTask, 0xFA)) != 0x4454) // 'TD'
- {
- FreeSelector(hMyTask);
- return 0; // no 'TD' signature: something wrong
- }
- hTask = *((WORD far *) MK_FP(hMyTask, 0x0c)); // the canonical hTask
- if (*((WORD far *) MK_FP(hTask, 0xFA)) != 0x4454) // 'TD'
- hTask = 0; // no 'TD' signature: something wrong
- FreeSelector(hMyTask);
- return hTask;
- }
-
- /* Turn hModule into hInstance: a module can have more than one
- instance, unless if it's a DLL. Use offset 0Eh in the Module Table,
- i.e., *((WORD far *) MK_FP(hModule, 0x0e)), to obtain the logical
- segment number (1, 2, etc.) of the DGROUP for the module. Then, look
- up the actual DGROUP selector in the segment portion of the module
- table. Treat this DGROUP as the hInstance. If the module is for a
- task rather than a DLL, the hInstance is for the most recent task
- that's still using the module table, and is not correct for the
- other invocations of the program.
- But a much simpler way is to get the hInstance returned from
- LoadLibrary(). This is used in hInstance_from_hModule. */
- /* That's what it says in the book. Unfortunately, it just doesn't
- seem totally reliable, so back to the long version: */
- #if 1
- typedef struct {
- unsigned short ns_sector;
- unsigned short ns_cbseg;
- unsigned short ns_flags;
- unsigned short ns_minalloc;
- unsigned short ns_seg; // in-memory version only!!!
- } SEG;
-
- // fields in Module Table
- #define DGROUP(lpNEhdr) *((WORD far *) &lpNEhdr[0x0e])
- #define SEGTAB(lpNEhdr) *((WORD far *) &lpNEhdr[0x22])
- #define CSEG(lpNEhdr) *((WORD far *) &lpNEhdr[0x1c])
-
- WORD hInstance_from_hModule(WORD hModHand)
- {
- BYTE far *nehdr;
- SEG far *segtab;
- WORD dgroup;
-
- if (! IsValidModuleHandle(hModHand))
- return 0;
-
- if (! IsModuleDLL(hModHand))
- /* DGROUP may not be unique! */ ;
-
- nehdr = MK_FP(hModHand, 0);
- segtab = MK_FP(hModHand, SEGTAB(nehdr));
- dgroup = DGROUP(nehdr);
-
- if (dgroup > CSEG(nehdr))
- return 0; // something wrong
- else
- return segtab[dgroup-1].ns_seg;
- }
- #else
- WORD hInstance_from_hModule(WORD hModule)
- {
- char buf[128];
- WORD hInstance;
- GetModuleFileName(hModule, buf, 128);
- /* remember, module is already loaded */
- if ((hInstance = LoadLibrary(buf)) > 32) // ref++
- {
- FreeLibrary(hInstance); // ref--
- return HIWORD(GlobalLock(hInstance));
- }
- else
- return 0;
- }
- #endif
-
- #define NEMAGIC 0x454E /* new EXE magic id: 'NE' */
- #define NEFLAGS_OFS 0x0c /* offset of flags in NE header */
- #define DLL_FLAG 0x8000 /* is module a DLL? */
-
- /* Is handle for a DLL rather than for a task? Use the flags at
- offset 0Ch in the Module Database */
- BOOL IsModuleDLL(HANDLE hModule)
- {
- if (*((WORD far *) MK_FP(hModule, 0)) != NEMAGIC)
- return FALSE; // it's not even a module, much less a DLL
- else
- return (*((WORD far *) MK_FP(hModule, NEFLAGS_OFS)) & DLL_FLAG);
- }
-
- /* C interface to protected-mode instructions; must compile
- with 286 instructions (Borland -2, Microsoft -G2) */
-
- /* Verify for Reading (VERR) instruction */
- BOOL verr(WORD wSel)
- {
- if (! wSel) return 0; /* workaround 386 bug: Hummel, p.584 */
- _asm verr word ptr wSel
- _asm je short ok
- return 0; // not valid for reading
- ok: return 1; // is valid for reading
- }
-
- /* Verify for Writing (VERW) instruction */
- BOOL verw(WORD wSel)
- {
- if (! wSel) return 0; /* workaround 386 bug: Hummel, p.585 */
- _asm verw word ptr wSel
- _asm je short ok
- return 0; // not valid for writing
- ok: return 1; // is valid for writing
- }
-
- /* C interface to protected-mode Load Access Rights (LAR) instruction */
- WORD lar(WORD wSel)
- {
- if (! wSel) return 0; /* workaround 386 bug: Hummel, p.448 */
- _asm lar ax, wSel
- _asm jnz error
- _asm shr ax, 8
- _asm jmp short no_error; // value in AX
- error:
- return 0;
- no_error: ;
- }
-
- /* C interface to LSL (Load Segment Limit) instruction */
- WORD lsl(WORD wSel)
- {
- if (! wSel) return 0; /* workaround 386 bug: Hummel, p.471 */
- _asm lsl ax, wSel
- _asm jnz error
- _asm jmp short non_error; // value in AX
- error:
- return 0;
- no_error: ;
- }
-
- /* Are we using the 16-bit or 32-bit KERNEL?
- Returns 16 for KRNL286, 32 for KRNL386, 0 for real mode */
- int Kernel1632(void)
- {
- LONG lFlags = GetWinFlags();
- if (GetVersion() == 0x0003) // Windows 3.0: mode-dependent
- {
- if (lFlags & WF_STANDARD) return 16;
- else if (lFlags & WF_ENHANCED) return 32;
- else /* yuk! real mode! */ return 0;
- }
- else // Windows 3.1+: processor-dependent
- return (lFlags & WF_CPU286) ? 16 : 32;
- }
-
- #define LHMAGIC 0x484C /* 'LH' signature for Local Heap */
- #define NEMAGIC 0x454E /* new EXE magic id: 'NE' */
- #define PSPMAGIC 0x20CD /* INT 20h instruction */
- #define TDBMAGIC 0x4454 /* 'TD' signature for Task */
-
- /* Does the far pointer point to a valid local heap info struct? */
- BOOL IsValidLocalHeap(BYTE far *fp)
- {
- WORD wMagicOffset = (Kernel1632() == 16) ? 0x22 : 0x28;
- return (*((WORD far *) &fp[wMagicOffset]) == LHMAGIC);
- }
-
- /* Is this handle for a Module Database? */
- BOOL IsValidModuleHandle(HANDLE h)
- {
- WORD far *fp;
- // assert(IsValidModuleHandle(GetCurrentModule()));
- if (! verr(h))
- return 0;
- fp = MK_FP(h, 0);
- return (*fp == NEMAGIC); // make sure starts with 'NE' signature
- }
-
- /* Is this handle for a DOS Program Segment Prefix (PSP; alias PDB)? */
- BOOL IsValidPSP(HANDLE h)
- {
- WORD far *fp;
- // assert(IsValidPSP(GetCurrentPDB()));
- if (! verr(h))
- return 0;
- fp = MK_FP(h, 0);
- return (*fp == PSPMAGIC); // make sure starts with INT 20h instruction
- }
-
- /* Is this handle for a Task Database? 3.1 has documented
- IsTask(), but it's not in 3.0, so do our own */
- BOOL IsValidTask(HANDLE h)
- {
- WORD far *fp;
- // assert(IsValidTask(GetCurrentTask()));
- if (! verr(h))
- return FALSE;
- if (GetSelectorLimit(h) < 0xFC)
- return FALSE;
- fp = MK_FP(h, 0xFA);
- return (*fp == TDBMAGIC);
- }
-