// // OSI.C // Operating System Independent DLL // * Graphical Output tracking (DDI hook/display driver) // * Window/Task tracking (Window hook) // // Copyright(c) Microsoft 1997- // #include #include #include 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); }