windows-nt/Source/XPSP1/NT/termsrv/remdsk/rds/as/as16/osi.c
2020-09-26 16:20:57 +08:00

729 lines
19 KiB
C

//
// OSI.C
// Operating System Independent DLL
// * Graphical Output tracking (DDI hook/display driver)
// * Window/Task tracking (Window hook)
//
// Copyright(c) Microsoft 1997-
//
#include <as16.h>
#include <version.h>
#include <ndcgver.h>
PALETTEENTRY CODESEG g_osiVgaPalette[16] =
{
{0x00, 0x00, 0x00, 0x00}, // Black 0x00
{0x80, 0x00, 0x00, 0x00}, // Dk Red 0x01
{0x00, 0x80, 0x00, 0x00}, // Dk Green 0x02
{0x80, 0x80, 0x00, 0x00}, // Dk Yellow 0x03
{0x00, 0x00, 0x80, 0x00}, // Dk Blue 0x04
{0x80, 0x00, 0x80, 0x00}, // Dk Purple 0x05
{0x00, 0x80, 0x80, 0x00}, // Dk Teal 0x06
{0xC0, 0xC0, 0xC0, 0x00}, // Gray 0x07
{0x80, 0x80, 0x80, 0x00}, // Dk Gray 0x08 or 0xF8
{0xFF, 0x00, 0x00, 0x00}, // Red 0x09 or 0xF9
{0x00, 0xFF, 0x00, 0x00}, // Green 0x0A or 0xFA
{0xFF, 0xFF, 0x00, 0x00}, // Yellow 0x0B or 0xFB
{0x00, 0x00, 0xFF, 0x00}, // Blue 0x0C or 0xFC
{0xFF, 0x00, 0xFF, 0x00}, // Purple 0x0D or 0xFD
{0x00, 0xFF, 0xFF, 0x00}, // Teal 0x0E or 0xFE
{0xFF, 0xFF, 0xFF, 0x00} // White 0x0F or 0xFF
};
// --------------------------------------------------------------------------
//
// DllEntryPoint
//
// --------------------------------------------------------------------------
BOOL WINAPI DllEntryPoint(DWORD dwReason, WORD hInst, WORD wDS,
WORD wHeapSize, DWORD dwReserved1, WORD wReserved2)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
// First app pulled us in
if (g_cProcesses++ == 0)
{
g_hInstAs16 = (HINSTANCE)hInst;
}
break;
case DLL_PROCESS_DETACH:
// Last app went away
if (--g_cProcesses == 0)
{
// Clean up anything that got left around
OSITerm16(TRUE);
}
break;
}
return(TRUE);
}
//
// OSILoad16
// Called on process attach of mnmcpi32.dll, to establish the flat thunks
// and return back our instance handle
//
void WINAPI OSILoad16
(
LPDWORD lpdwInstance
)
{
DebugEntry(OSI_Load16);
*lpdwInstance = (DWORD)(UINT)g_hInstAs16;
DebugExitVOID(OSI_Load16);
}
// --------------------------------------------------------------------------
//
// OSIInit16
//
// Inits binary patcher, gdi + user patching, windows hooks, etc.
//
// --------------------------------------------------------------------------
BOOL WINAPI OSIInit16
(
DWORD version,
HWND hwndCore,
LPDWORD ppSharedMem,
LPDWORD ppoaSharedMem,
LPDWORD ppimSharedMem,
LPDWORD lpsbcEnabled,
LPDWORD ppShuntBuffers,
LPDWORD pBitmasks
)
{
BOOL rc = FALSE;
HGLOBAL hMem;
HMODULE hModDisplay;
DebugEntry(OSIInit16);
//
// Fill in our instance handle. We always return this so the 32-bit
// code can free our library after having loaded it.
//
*lpsbcEnabled = FALSE;
#ifdef DEBUG
g_imSharedData.cbSize = sizeof(g_imSharedData);
#endif
*ppimSharedMem = (DWORD)MapSL(&g_imSharedData);
ASSERT(*ppimSharedMem);
if (version != DCS_MAKE_VERSION())
{
ERROR_OUT(("OSIInit16: failing, version mismatch 0x%lx (core) 0x%lx (dd)",
version, DCS_MAKE_VERSION()));
DC_QUIT;
}
// ONLY ALLOW ONE CLIENT TO INITIALIZE
if (g_asMainWindow != NULL)
{
WARNING_OUT(("OSIInit16: mnmas16.dll was left around last time"));
// If this task is no longer valid, then cleanup for it
if (IsWindow(g_asMainWindow))
{
//
// Uh oh. Somehow a previous version of NM is still around.
// Do the safest thing--refuse to share.
//
ERROR_OUT(("OSIInit16: Another version of NetMeeting is still running!"));
DC_QUIT;
}
// Cleanup (this is similar to the NT dd code)
OSITerm16(TRUE);
ASSERT(!g_asMainWindow);
}
//
// Clear out shared IM memory.
//
g_imSharedData.imSuspended = FALSE;
g_imSharedData.imControlled = FALSE;
g_imSharedData.imPaused = FALSE;
g_imSharedData.imUnattended = FALSE;
g_asMainWindow = hwndCore;
ASSERT(g_asMainWindow);
g_hCoreTask = GetCurrentTask();
g_osiDesktopWindow = GetDesktopWindow();
ASSERT(g_osiDesktopWindow);
//
// DISPLAY DRIVER STUFF
//
hModDisplay = GetModuleHandle("DISPLAY");
g_lpfnSetCursor = (SETCURSORPROC)GetProcAddress(hModDisplay,
MAKEINTRESOURCE(ORD_OEMSETCURSOR));
if (!hModDisplay || !g_lpfnSetCursor)
{
ERROR_OUT(("Couldn't find cursor entry points"));
DC_QUIT;
}
// This doesn't always exist
g_lpfnSaveBits = (SAVEBITSPROC)GetProcAddress(hModDisplay,
MAKEINTRESOURCE(ORD_OEMSAVEBITS));
//
// KERNEL16 AND KERNEL32 STUFF
//
//
// Get KRNL16's instance/module handle
//
g_hInstKrnl16 = LoadLibrary("KRNL386.EXE");
ASSERT(g_hInstKrnl16);
FreeLibrary(g_hInstKrnl16);
g_hModKrnl16 = GetExePtr(g_hInstKrnl16);
ASSERT(g_hModKrnl16);
//
// Get KERNEL32's instance/module handle
//
g_hInstKrnl32 = GetModuleHandle32("KERNEL32.DLL");
ASSERT(g_hInstKrnl32);
//
// Get mapped 16-bit equivalent of KERNEL32's instance handle
//
g_hInstKrnl32MappedTo16 = MapInstance32(g_hInstKrnl32);
ASSERT(g_hInstKrnl32MappedTo16);
//
// Get hold of MultiByteToWideChar() routine
//
g_lpfnAnsiToUni = (ANSITOUNIPROC)GetProcAddress32(g_hInstKrnl32,
"MultiByteToWideChar");
ASSERT(g_lpfnAnsiToUni);
//
// GDI16 AND GDI32 STUFF
//
//
// Get GDI16's instance/module handle
//
g_hInstGdi16 = LoadLibrary("GDI.EXE");
ASSERT(g_hInstGdi16);
FreeLibrary(g_hInstGdi16);
g_hModGdi16 = GetExePtr(g_hInstGdi16);
ASSERT(g_hModGdi16);
//
// Get GDI32's instance/module handle
//
g_hInstGdi32 = GetModuleHandle32("GDI32.DLL");
ASSERT(g_hInstGdi32);
//
// Get hold of GDI16 functions not exported but which are the target of
// public GDI32 functions via flat thunks
//
if (!GetGdi32OnlyExport("ExtTextOutW", 0, (FARPROC FAR*)&g_lpfnExtTextOutW) ||
!GetGdi32OnlyExport("TextOutW", 0, (FARPROC FAR*)&g_lpfnTextOutW) ||
!GetGdi32OnlyExport("PolylineTo", 0, (FARPROC FAR*)&g_lpfnPolylineTo) ||
!GetGdi32OnlyExport("PolyPolyline", 18, (FARPROC FAR*)&g_lpfnPolyPolyline))
{
ERROR_OUT(("Couldn't get hold of GDI32 routines"));
DC_QUIT;
}
ASSERT(g_lpfnExtTextOutW);
ASSERT(g_lpfnTextOutW);
ASSERT(g_lpfnPolylineTo);
ASSERT(g_lpfnPolyPolyline);
//
// USER16 and USER32 STUFF
//
//
// Get USER16's instance/module handle
//
g_hInstUser16 = LoadLibrary("USER.EXE");
ASSERT(g_hInstUser16);
FreeLibrary(g_hInstUser16);
g_hModUser16 = GetExePtr(g_hInstUser16);
ASSERT(g_hModUser16);
//
// Get hold of USER32's instance handle. It has functions we
// want to call which USER16 doesn't export.
//
g_hInstUser32 = GetModuleHandle32("USER32.DLL");
ASSERT(g_hInstUser32);
//
// Get hold of USER16 functions not exported but which are the target of
// public USER32 functions via flat thunks
//
if (!GetUser32OnlyExport("GetWindowThreadProcessId", (FARPROC FAR*)&g_lpfnGetWindowThreadProcessId))
{
ERROR_OUT(("Couldn't get hold of USER32 routines"));
DC_QUIT;
}
ASSERT(g_lpfnGetWindowThreadProcessId);
//
// This exists in Memphis but not Win95
//
g_lpfnCDSEx = (CDSEXPROC)GetProcAddress(g_hModUser16, "ChangeDisplaySettingsEx");
//
// Allocate the shared memory we use to communicate with the 32-bit
// share core.
//
ASSERT(!g_asSharedMemory);
ASSERT(!g_poaData[0]);
ASSERT(!g_poaData[1]);
//
// Allocate our blocks GMEM_SHARE so we aren't bound by the vagaries
// of process ownership. We want our DLL to control them. Note that
// we do the same thing with GDI objects we create--our module owns the.
//
// We use GMEM_FIXED since we map these to flat addresses for mnmcpi32.dll,
// and we don't want the linear address of these memory blocks to move
// afterwards.
//
hMem = GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT | GMEM_SHARE, sizeof(SHM_SHARED_MEMORY));
g_asSharedMemory = MAKELP(hMem, 0);
hMem = GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT | GMEM_SHARE, sizeof(OA_SHARED_DATA));
g_poaData[0] = MAKELP(hMem, 0);
hMem = GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT | GMEM_SHARE, sizeof(OA_SHARED_DATA));
g_poaData[1] = MAKELP(hMem, 0);
if (!g_asSharedMemory ||
!g_poaData[0] ||
!g_poaData[1])
{
ERROR_OUT(("OSIInit16: couldn't allocate shared memory blocks"));
DC_QUIT;
}
//
// Get current screen attributes
//
g_oeStockPalette = GetStockObject(DEFAULT_PALETTE);
g_osiScreenRect.left = 0;
g_osiScreenRect.top = 0;
g_osiScreenRect.right = GetSystemMetrics(SM_CXSCREEN);
g_osiScreenRect.bottom = GetSystemMetrics(SM_CYSCREEN);
g_osiScreenDC = CreateDC("DISPLAY", 0L, 0L, 0L);
g_osiMemoryDC = CreateCompatibleDC(g_osiScreenDC);
g_osiMemoryBMP = CreateCompatibleBitmap(g_osiScreenDC, 1, 1);
if (!g_osiScreenDC || !g_osiMemoryDC || !g_osiMemoryBMP)
{
ERROR_OUT(("Couldn't get screen dc"));
DC_QUIT;
}
SetObjectOwner(g_osiScreenDC, g_hInstAs16);
SetObjectOwner(g_osiMemoryDC, g_hInstAs16);
SetObjectOwner(g_osiMemoryBMP, g_hInstAs16);
MakeObjectPrivate(g_osiMemoryBMP, TRUE);
g_osiScreenBitsPlane = GetDeviceCaps(g_osiScreenDC, BITSPIXEL);
g_osiScreenPlanes = GetDeviceCaps(g_osiScreenDC, PLANES);
g_osiScreenBPP = (g_osiScreenBitsPlane * g_osiScreenPlanes);
//
// Get the color masks
//
g_osiScreenRedMask = 0x000000FF;
g_osiScreenGreenMask = 0x0000FF00;
g_osiScreenBlueMask = 0x00FF0000;
//
// Only displays with more than 8bpp (palettized) might have color
// masks. Use our 1 pixel scratch bitmap to get them.
//
if (g_osiScreenBPP > 8)
{
DIB4 dib4T;
//
// Get the header
//
dib4T.bi.biSize = sizeof(BITMAPINFOHEADER);
dib4T.bi.biBitCount = 0;
GetDIBits(g_osiScreenDC, g_osiMemoryBMP, 0, 1, NULL, (LPBITMAPINFO)&dib4T.bi,
DIB_RGB_COLORS);
//
// Get the mask
//
GetDIBits(g_osiScreenDC, g_osiMemoryBMP, 0, 1, NULL, (LPBITMAPINFO)&dib4T.bi,
DIB_RGB_COLORS);
if (dib4T.bi.biCompression == BI_BITFIELDS)
{
g_osiScreenRedMask = dib4T.ct[0];
g_osiScreenGreenMask = dib4T.ct[1];
g_osiScreenBlueMask = dib4T.ct[2];
}
}
g_osiMemoryOld = SelectBitmap(g_osiMemoryDC, g_osiMemoryBMP);
//
// Initialize the bmiHeader so OEConvertColor() doesn't have to do it
// over and over, when the header isn't touched by GDI.
//
g_osiScreenBMI.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
g_osiScreenBMI.bmiHeader.biPlanes = 1;
g_osiScreenBMI.bmiHeader.biBitCount = g_osiScreenBPP;
g_osiScreenBMI.bmiHeader.biCompression = BI_RGB;
g_osiScreenBMI.bmiHeader.biSizeImage = 0;
g_osiScreenBMI.bmiHeader.biXPelsPerMeter = 1000;
g_osiScreenBMI.bmiHeader.biYPelsPerMeter = 1000;
g_osiScreenBMI.bmiHeader.biClrUsed = 0;
g_osiScreenBMI.bmiHeader.biClrImportant = 0;
g_osiScreenBMI.bmiHeader.biWidth = 1;
g_osiScreenBMI.bmiHeader.biHeight = 1;
//
// Init the various display driver components
//
BA_DDInit();
if (!CM_DDInit(g_osiScreenDC))
{
ERROR_OUT(("CM failed to init"));
DC_QUIT;
}
if (!SSI_DDInit())
{
ERROR_OUT(("SSI failed to init"));
DC_QUIT;
}
if (!OE_DDInit())
{
ERROR_OUT(("OE failed to init"));
DC_QUIT;
}
if (!IM_DDInit())
{
ERROR_OUT(("IM failed to init"));
DC_QUIT;
}
if (!HET_DDInit())
{
ERROR_OUT(("HET failed to init"));
DC_QUIT;
}
//
// If we're here, all succeeded initializing
//
//
// Map ptrs to flat addresses so they can be used in 32-bit code. This
// can't fail unless kernel is so messed up Windows is about to keel
// over and die.
//
ASSERT(ppSharedMem);
*ppSharedMem = (DWORD)MapSL(g_asSharedMemory);
ASSERT(*ppSharedMem);
ASSERT(ppoaSharedMem);
ppoaSharedMem[0] = (DWORD)MapSL(g_poaData[0]);
ASSERT(ppoaSharedMem[0]);
ppoaSharedMem[1] = (DWORD)MapSL(g_poaData[1]);
ASSERT(ppoaSharedMem[1]);
rc = TRUE;
DC_EXIT_POINT:
DebugExitBOOL(OSIInit16, rc);
return(rc);
}
// --------------------------------------------------------------------------
//
// OSITerm16
// Cleans up binary patcher, gdi + user patching, windows hooks, etc.
//
// We do this on normal OSI stop, and on catastrophic failure.
//
// --------------------------------------------------------------------------
void WINAPI OSITerm16(BOOL fUnloading)
{
DebugEntry(OSITerm16);
if (!g_hCoreTask)
{
// Nothing to cleanup.
DC_QUIT;
}
//
// Is the task that actually caused us to allocate our resources? In
// other words, we don't want to clean up if
// App A loads mnmas16.dll, and gets it inited
// App B somehow starts up, loads mnmas16.dll, but mnmas16.dll
// doesn't init for sharing because cProcesses is > 1
// App B shuts down
// App B calls OSITerm16
//
// So in the 'dll is really about to go away case', we always cleanup.
// But in normal term of sharing, we cleanup if the current task is the
// current one.
//
if (fUnloading || (g_hCoreTask == GetCurrentTask()))
{
//
// Term other pieces that depend on layout of shared memory
//
HET_DDTerm();
IM_DDTerm();
OE_DDTerm();
SSI_DDTerm();
CM_DDTerm();
//
// Free memory blocks
//
if (g_poaData[1])
{
GlobalFree((HGLOBAL)SELECTOROF(g_poaData[1]));
g_poaData[1] = NULL;
}
if (g_poaData[0])
{
GlobalFree((HGLOBAL)SELECTOROF(g_poaData[0]));
g_poaData[0] = NULL;
}
if (g_asSharedMemory)
{
GlobalFree((HGLOBAL)SELECTOROF(g_asSharedMemory));
g_asSharedMemory = NULL;
}
if (g_osiMemoryOld)
{
SelectBitmap(g_osiMemoryDC, g_osiMemoryOld);
g_osiMemoryOld = NULL;
}
if (g_osiMemoryBMP)
{
SysDeleteObject(g_osiMemoryBMP);
g_osiMemoryBMP = NULL;
}
if (g_osiMemoryDC)
{
DeleteDC(g_osiMemoryDC);
g_osiMemoryDC = NULL;
}
if (g_osiScreenDC)
{
DeleteDC(g_osiScreenDC);
g_osiScreenDC = NULL;
}
g_asMainWindow = NULL;
g_hCoreTask = NULL;
}
DC_EXIT_POINT:
DebugExitVOID(OSITerm16);
}
// --------------------------------------------------------------------------
//
// OSIFunctionRequest16
//
// Communication function with 32-bit MNMCPI32.DLL
//
// --------------------------------------------------------------------------
BOOL WINAPI OSIFunctionRequest16(DWORD fnEscape, LPOSI_ESCAPE_HEADER lpOsiEsc,
DWORD cbEscInfo)
{
BOOL rc = FALSE;
DebugEntry(OSIFunctionRequest16);
//
// Check the data is long enough to store our standard escape header.
// If it is not big enough this must be an escape request for another
// driver.
//
if (cbEscInfo < sizeof(OSI_ESCAPE_HEADER))
{
ERROR_OUT(("Escape block not big enough"));
DC_QUIT;
}
//
// Check for our escape ID. If it is not our escape ID this must be an
// escape request for another driver.
//
if (lpOsiEsc->identifier != OSI_ESCAPE_IDENTIFIER)
{
ERROR_OUT(("Bogus Escape header ID"));
DC_QUIT;
}
else if (lpOsiEsc->version != DCS_MAKE_VERSION())
{
ERROR_OUT(("Mismatched display driver and NetMeeting"));
DC_QUIT;
}
if ((fnEscape >= OSI_ESC_FIRST) && (fnEscape <= OSI_ESC_LAST))
{
rc = OSI_DDProcessRequest((UINT)fnEscape, lpOsiEsc, cbEscInfo);
}
else if ((fnEscape >= OSI_OE_ESC_FIRST) && (fnEscape <= OSI_OE_ESC_LAST))
{
rc = OE_DDProcessRequest((UINT)fnEscape, lpOsiEsc, cbEscInfo);
}
else if ((fnEscape >= OSI_HET_ESC_FIRST) && (fnEscape <= OSI_HET_ESC_LAST))
{
rc = HET_DDProcessRequest((UINT)fnEscape, lpOsiEsc, cbEscInfo);
}
else if ((fnEscape >= OSI_SBC_ESC_FIRST) && (fnEscape <= OSI_SBC_ESC_LAST))
{
// Do nothing
}
else if ((fnEscape >= OSI_SSI_ESC_FIRST) && (fnEscape <= OSI_SSI_ESC_LAST))
{
rc = SSI_DDProcessRequest((UINT)fnEscape, lpOsiEsc, cbEscInfo);
}
else if ((fnEscape >= OSI_CM_ESC_FIRST) && (fnEscape <= OSI_CM_ESC_LAST))
{
rc = CM_DDProcessRequest((UINT)fnEscape, lpOsiEsc, cbEscInfo);
}
else if ((fnEscape >= OSI_OA_ESC_FIRST) && (fnEscape <= OSI_OA_ESC_LAST))
{
rc = OA_DDProcessRequest((UINT)fnEscape, lpOsiEsc, cbEscInfo);
}
else if ((fnEscape >= OSI_BA_ESC_FIRST) && (fnEscape <= OSI_BA_ESC_LAST))
{
rc = BA_DDProcessRequest((UINT)fnEscape, lpOsiEsc, cbEscInfo);
}
else if ((fnEscape >= OSI_HET_WO_ESC_FIRST) && (fnEscape <= OSI_HET_WO_ESC_LAST))
{
rc = HET_DDProcessRequest((UINT)fnEscape, lpOsiEsc, cbEscInfo);
}
else
{
ERROR_OUT(("Unknown function request"));
}
DC_EXIT_POINT:
DebugExitBOOL(OSIFunctionRequest16, rc);
return(rc);
}
//
// OSI_DDProcessRequest()
// Handles OSI generic escapes
//
BOOL OSI_DDProcessRequest
(
UINT fnEscape,
LPOSI_ESCAPE_HEADER pResult,
DWORD cbResult
)
{
BOOL rc;
DebugEntry(OSI_DDProcessRequest);
switch (fnEscape)
{
case OSI_ESC_SYNC_NOW:
{
ASSERT(cbResult == sizeof(OSI_ESCAPE_HEADER));
//
// Resync with the 32-bit ring 3 core. This happens when
// somebody joins or leaves a share.
//
BA_ResetBounds();
OA_DDSyncUpdatesNow();
rc = TRUE;
}
break;
default:
{
ERROR_OUT(("Unrecognized OSI escape"));
rc = FALSE;
}
break;
}
DebugExitBOOL(OSI_DDProcessRequest, rc);
return(rc);
}