Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/external/source/vncdll/winvnc/VideoDriver.cpp
Views: 11780
// Copyright (C) 2005-2006 Lev Kazarkin. All Rights Reserved.1//2// TightVNC is free software; you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation; either version 2 of the License, or5// (at your option) any later version.6//7// This program is distributed in the hope that it will be useful,8// but WITHOUT ANY WARRANTY; without even the implied warranty of9// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the10// GNU General Public License for more details.11//12// You should have received a copy of the GNU General Public License13// along with this program; if not, write to the Free Software14// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,15// USA.16//17// TightVNC distribution homepage on the Web: http://www.tightvnc.com/1819#include "VideoDriver.h"20#include "vncDesktop.h"2122char vncVideoDriver::szDriverString[] = "Mirage Driver";23char vncVideoDriver::szDriverStringAlt[] = "DemoForge Mirage Driver";24char vncVideoDriver::szMiniportName[] = "dfmirage";2526#define MINIPORT_REGISTRY_PATH "SYSTEM\\CurrentControlSet\\Hardware Profiles\\Current\\System\\CurrentControlSet\\Services"2728BOOL IsWinNT();29BOOL IsNtVer(ULONG mj, ULONG mn);30BOOL IsWinVerOrHigher(ULONG mj, ULONG mn);313233vncVideoDriver::vncVideoDriver()34{35bufdata.buffer = NULL;36bufdata.Userbuffer = NULL;37m_fIsActive = false;38m_fDirectAccessInEffect = false;39m_fHandleScreen2ScreenBlt = false;40*m_devname= 0;41m_drv_ver_mj = 0;42m_drv_ver_mn = 0;43}4445vncVideoDriver::~vncVideoDriver()46{47UnMapSharedbuffers();48Deactivate();49_ASSERTE(!m_fIsActive);50_ASSERTE(!m_fDirectAccessInEffect);51}5253#define BYTE0(x) ((x) & 0xFF)54#define BYTE1(x) (((x) >> 8) & 0xFF)55#define BYTE2(x) (((x) >> 16) & 0xFF)56#define BYTE3(x) (((x) >> 24) & 0xFF)5758BOOL vncVideoDriver::CheckVersion()59{60_ASSERTE(IsWinNT());6162HDC l_gdc= ::CreateDC(m_devname, NULL, NULL, NULL);63if (!l_gdc)64{65return FALSE;66}6768Esc_dmf_Qvi_IN qvi_in;69qvi_in.cbSize = sizeof(qvi_in);7071qvi_in.app_actual_version = DMF_PROTO_VER_CURRENT;72qvi_in.display_minreq_version = DMF_PROTO_VER_MINCOMPAT;73qvi_in.connect_options = 0;7475Esc_dmf_Qvi_OUT qvi_out;76qvi_out.cbSize = sizeof(qvi_out);7778int drvCr = ExtEscape(79l_gdc,80ESC_QVI,81sizeof(qvi_in), (LPSTR) &qvi_in,82sizeof(qvi_out), (LPSTR) &qvi_out);83DeleteDC(l_gdc);8485if (drvCr == 0)86{87return FALSE;88}8990if (drvCr < 0)91{92return FALSE;93}9495m_drv_ver_mj = BYTE3(qvi_out.display_actual_version);96m_drv_ver_mn = BYTE2(qvi_out.display_actual_version);9798return TRUE;99}100101BOOL vncVideoDriver::MapSharedbuffers(BOOL fForDirectScreenAccess)102{103_ASSERTE(!m_fIsActive);104_ASSERTE(!m_fDirectAccessInEffect);105_ASSERTE(IsWinNT());106107HDC l_gdc= ::CreateDC(m_devname, NULL, NULL, NULL);108if (!l_gdc)109{110return FALSE;111}112113oldCounter = 0;114int drvCr = ExtEscape(115l_gdc,116MAP1,1170, NULL,118sizeof(GETCHANGESBUF), (LPSTR) &bufdata);119DeleteDC(l_gdc);120121if (drvCr <= 0)122{123return FALSE;124}125m_fIsActive = true;126if (fForDirectScreenAccess)127{128if (!bufdata.Userbuffer)129{130return FALSE;131}132m_fDirectAccessInEffect = true;133}134135// Screen2Screen support added in Mirage ver 1.2136m_fHandleScreen2ScreenBlt = (m_drv_ver_mj > 1) || (m_drv_ver_mj == 1 && m_drv_ver_mn >= 2);137138return TRUE;139}140141BOOL vncVideoDriver::TestMapped()142{143_ASSERTE(IsWinNT());144145TCHAR *pDevName;146if (IsWinVerOrHigher(5, 0))147{148DISPLAY_DEVICE dd;149INT devNum = 0;150if (!LookupVideoDeviceAlt(szDriverString, szDriverStringAlt, devNum, &dd))151return FALSE;152pDevName = (TCHAR *)dd.DeviceName;153}154else155{156pDevName = "DISPLAY";157}158159HDC l_ddc = ::CreateDC(pDevName, NULL, NULL, NULL);160if (l_ddc)161{162BOOL b = ExtEscape(l_ddc, TESTMAPPED, 0, NULL, 0, NULL);163DeleteDC(l_ddc);164return b;165}166return FALSE;167}168169void vncVideoDriver::UnMapSharedbuffers()170{171_ASSERTE(IsWinNT());172173int DrvCr = 0;174if (m_devname[0])175{176_ASSERTE(m_fIsActive);177_ASSERTE(bufdata.buffer);178_ASSERTE(!m_fDirectAccessInEffect || bufdata.Userbuffer);179180HDC l_gdc= ::CreateDC(m_devname, NULL, NULL, NULL);181if (l_gdc)182{183DrvCr = ExtEscape(184l_gdc,185UNMAP1,186sizeof(GETCHANGESBUF), (LPSTR) &bufdata,1870, NULL);188DeleteDC(l_gdc);189190_ASSERTE(DrvCr > 0);191}192}193// 0 return value is unlikely for Mirage because its DC is independent194// from the reference device;195// this happens with Quasar if its mode was changed externally.196// nothing is particularly bad with it.197198if (DrvCr <= 0)199{200if (bufdata.buffer)201{202BOOL br = UnmapViewOfFile(bufdata.buffer);203}204if (bufdata.Userbuffer)205{206BOOL br = UnmapViewOfFile(bufdata.Userbuffer);207}208}209m_fIsActive = false;210m_fDirectAccessInEffect = false;211m_fHandleScreen2ScreenBlt = false;212}213214template <class TpFn>215HINSTANCE LoadNImport(LPCTSTR szDllName, LPCTSTR szFName, TpFn &pfn)216{217HINSTANCE hDll = LoadLibrary(szDllName);218if (hDll)219{220pfn = (TpFn)GetProcAddress(hDll, szFName);221if (pfn)222return hDll;223FreeLibrary(hDll);224}225return NULL;226}227228//BOOL vncVideoDriver::LookupVideoDevice(LPCTSTR szDeviceString, INT &devNum, DISPLAY_DEVICE *pDd)229BOOL vncVideoDriver::LookupVideoDeviceAlt(230LPCTSTR szDevStr,231LPCTSTR szDevStrAlt,232INT &devNum,233DISPLAY_DEVICE *pDd)234{235_ASSERTE(IsWinVerOrHigher(5, 0));236237pEnumDisplayDevices pd = NULL;238HINSTANCE hInstUser32 = LoadNImport("User32.DLL", "EnumDisplayDevicesA", pd);239if (!hInstUser32) return FALSE;240241ZeroMemory(pDd, sizeof(DISPLAY_DEVICE));242pDd->cb = sizeof(DISPLAY_DEVICE);243BOOL result;244while (result = (*pd)(NULL,devNum, pDd, 0))245{246if (strcmp((const char *)pDd->DeviceString, szDevStr) == 0 ||247szDevStrAlt && strcmp((const char *)pDd->DeviceString, szDevStrAlt) == 0)248{249break;250}251devNum++;252}253254FreeLibrary(hInstUser32);255return result;256}257258HKEY vncVideoDriver::CreateDeviceKey(LPCTSTR szMpName)259{260HKEY hKeyProfileMirror = (HKEY)0;261if (RegCreateKey(262HKEY_LOCAL_MACHINE,263(MINIPORT_REGISTRY_PATH),264&hKeyProfileMirror) != ERROR_SUCCESS)265{266return FALSE;267}268HKEY hKeyProfileMp = (HKEY)0;269LONG cr = RegCreateKey(270hKeyProfileMirror,271szMpName,272&hKeyProfileMp);273RegCloseKey(hKeyProfileMirror);274if (cr != ERROR_SUCCESS)275{276return FALSE;277}278HKEY hKeyDevice = (HKEY)0;279if (RegCreateKey(280hKeyProfileMp,281("DEVICE0"),282&hKeyDevice) != ERROR_SUCCESS)283{284285}286RegCloseKey(hKeyProfileMp);287return hKeyDevice;288}289290BOOL vncVideoDriver::Activate(291BOOL fForDirectAccess,292const RECT *prcltarget)293{294_ASSERTE(IsWinNT());295296if (IsWinVerOrHigher(5, 0))297{298return Activate_NT50(fForDirectAccess, prcltarget);299}300else301{302// NOTE: prcltarget is just a SourceDisplayRect.303// there is only 1 possibility on NT4, so safely ignore it304return Activate_NT46(fForDirectAccess);305}306}307308void vncVideoDriver::Deactivate()309{310_ASSERTE(IsWinNT());311312if (IsWinVerOrHigher(5, 0))313{314Deactivate_NT50();315}316else317{318Deactivate_NT46();319}320}321322BOOL vncVideoDriver::Activate_NT50(323BOOL fForDirectAccess,324const RECT *prcltarget)325{326HDESK hdeskInput;327HDESK hdeskCurrent;328329DISPLAY_DEVICE dd;330INT devNum = 0;331if (!LookupVideoDeviceAlt(szDriverString, szDriverStringAlt, devNum, &dd))332{333return FALSE;334}335336DEVMODE devmode;337FillMemory(&devmode, sizeof(DEVMODE), 0);338devmode.dmSize = sizeof(DEVMODE);339devmode.dmDriverExtra = 0;340BOOL change = EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devmode);341devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;342if (prcltarget)343{344// we always have to set position or345// a stale position info in registry would come into effect.346devmode.dmFields |= DM_POSITION;347devmode.dmPosition.x = prcltarget->left;348devmode.dmPosition.y = prcltarget->top;349350devmode.dmPelsWidth = prcltarget->right - prcltarget->left;351devmode.dmPelsHeight = prcltarget->bottom - prcltarget->top;352}353354devmode.dmDeviceName[0] = '\0';355356HKEY hKeyDevice = CreateDeviceKey(szMiniportName);357if (hKeyDevice == NULL)358return FALSE;359360// TightVNC does not use these features361RegDeleteValue(hKeyDevice, ("Screen.ForcedBpp"));362RegDeleteValue(hKeyDevice, ("Pointer.Enabled"));363364DWORD dwVal = fForDirectAccess ? 3 : 0;365// NOTE that old driver ignores it and mapping is always ON with it366if (RegSetValueEx(367hKeyDevice,368("Cap.DfbBackingMode"),3690,370REG_DWORD,371(unsigned char *)&dwVal,3724) != ERROR_SUCCESS)373{374return FALSE;375}376377dwVal = 1;378if (RegSetValueEx(379hKeyDevice,380("Order.BltCopyBits.Enabled"),3810,382REG_DWORD,383(unsigned char *)&dwVal,3844) != ERROR_SUCCESS)385{386return FALSE;387}388389dwVal = 1;390if (RegSetValueEx(391hKeyDevice,392("Attach.ToDesktop"),3930,394REG_DWORD,395(unsigned char *)&dwVal,3964) != ERROR_SUCCESS)397{398return FALSE;399}400401pChangeDisplaySettingsEx pCDS = NULL;402HINSTANCE hInstUser32 = LoadNImport("User32.DLL", "ChangeDisplaySettingsExA", pCDS);403if (!hInstUser32) return FALSE;404405// Save the current desktop406hdeskCurrent = GetThreadDesktop(GetCurrentThreadId());407if (hdeskCurrent != NULL)408{409hdeskInput = OpenInputDesktop(0, FALSE, MAXIMUM_ALLOWED);410if (hdeskInput != NULL)411SetThreadDesktop(hdeskInput);412}413// 24 bpp screen mode is MUNGED to 32 bpp.414// the underlying buffer format must be 32 bpp.415// see vncDesktop::ThunkBitmapInfo()416if (devmode.dmBitsPerPel==24) devmode.dmBitsPerPel = 32;417LONG cr = (*pCDS)(418(TCHAR *)dd.DeviceName,419&devmode,420NULL,421CDS_UPDATEREGISTRY,NULL);422423strcpy(m_devname, (const char *)dd.DeviceName);424425// Reset desktop426SetThreadDesktop(hdeskCurrent);427// Close the input desktop428CloseDesktop(hdeskInput);429RegCloseKey(hKeyDevice);430FreeLibrary(hInstUser32);431432return TRUE;433}434435BOOL vncVideoDriver::Activate_NT46(BOOL fForDirectAccess)436{437HKEY hKeyDevice = CreateDeviceKey(szMiniportName);438if (hKeyDevice == NULL)439return FALSE;440441// TightVNC does not use these features442RegDeleteValue(hKeyDevice, ("Screen.ForcedBpp"));443RegDeleteValue(hKeyDevice, ("Pointer.Enabled"));444445DWORD dwVal = fForDirectAccess ? 3 : 0;446// NOTE that old driver ignores it and mapping is always ON with it447if (RegSetValueEx(448hKeyDevice,449("Cap.DfbBackingMode"),4500,451REG_DWORD,452(unsigned char *)&dwVal,4534) != ERROR_SUCCESS)454{455return FALSE;456}457458dwVal = 1;459if (RegSetValueEx(460hKeyDevice,461("Order.BltCopyBits.Enabled"),4620,463REG_DWORD,464(unsigned char *)&dwVal,4654) != ERROR_SUCCESS)466{467return FALSE;468}469470// NOTE: we cannot truly load the driver471// but ChangeDisplaySettings makes PDEV to reload472// and thus new settings come into effect473474// TODO475476strcpy(m_devname, "DISPLAY");477478RegCloseKey(hKeyDevice);479return TRUE;480}481482void vncVideoDriver::Deactivate_NT50()483{484HDESK hdeskInput;485HDESK hdeskCurrent;486487// it is important to us to be able to deactivate488// even what we have never activated. thats why we look it up, all over489// if (!m_devname[0])490// return;491// ... and forget the name492*m_devname = 0;493494DISPLAY_DEVICE dd;495INT devNum = 0;496if (!LookupVideoDeviceAlt(szDriverString, szDriverStringAlt, devNum, &dd))497{498return;499}500501DEVMODE devmode;502FillMemory(&devmode, sizeof(DEVMODE), 0);503devmode.dmSize = sizeof(DEVMODE);504devmode.dmDriverExtra = 0;505BOOL change = EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devmode);506devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;507devmode.dmDeviceName[0] = '\0';508509HKEY hKeyDevice = CreateDeviceKey(szMiniportName);510if (hKeyDevice == NULL)511return;512513DWORD one = 0;514if (RegSetValueEx(hKeyDevice,("Attach.ToDesktop"), 0, REG_DWORD, (unsigned char *)&one,4) != ERROR_SUCCESS)515{516517}518519// reverting to default behavior520RegDeleteValue(hKeyDevice, ("Cap.DfbBackingMode"));521RegDeleteValue(hKeyDevice, ("Order.BltCopyBits.Enabled"));522523pChangeDisplaySettingsEx pCDS = NULL;524HINSTANCE hInstUser32 = LoadNImport("User32.DLL", "ChangeDisplaySettingsExA", pCDS);525if (!hInstUser32) return;526527// Save the current desktop528hdeskCurrent = GetThreadDesktop(GetCurrentThreadId());529if (hdeskCurrent != NULL)530{531hdeskInput = OpenInputDesktop(0, FALSE, MAXIMUM_ALLOWED);532if (hdeskInput != NULL)533SetThreadDesktop(hdeskInput);534}535// 24 bpp screen mode is MUNGED to 32 bpp. see vncDesktop::ThunkBitmapInfo()536if (devmode.dmBitsPerPel==24) devmode.dmBitsPerPel = 32;537538// Add 'Default.*' settings to the registry under above hKeyProfile\mirror\device539(*pCDS)((TCHAR *)dd.DeviceName, &devmode, NULL, CDS_UPDATEREGISTRY, NULL);540541// Reset desktop542SetThreadDesktop(hdeskCurrent);543// Close the input desktop544CloseDesktop(hdeskInput);545RegCloseKey(hKeyDevice);546FreeLibrary(hInstUser32);547}548549void vncVideoDriver::Deactivate_NT46()550{551// ... and forget the name552*m_devname = 0;553554HKEY hKeyDevice = CreateDeviceKey(szMiniportName);555if (hKeyDevice == NULL)556return;557558// reverting to default behavior559RegDeleteValue(hKeyDevice, ("Cap.DfbBackingMode"));560561// RegDeleteValue(hKeyDevice, ("Order.BltCopyBits.Enabled"));562// TODO: remove "Order.BltCopyBits.Enabled"563// now we don't touch this important option564// because we dont apply the changed values565566RegCloseKey(hKeyDevice);567}568569void vncVideoDriver::HandleDriverChanges(570vncDesktop *pDesk,571vncRegion &rgn,572int xoffset,573int yoffset,574BOOL &bPointerShapeChange)575{576ULONG snapshot_counter = bufdata.buffer->counter;577if (oldCounter == snapshot_counter)578return;579580if (oldCounter < snapshot_counter)581{582HandleDriverChangesSeries(583pDesk,584rgn,585xoffset, yoffset,586bufdata.buffer->pointrect + oldCounter,587bufdata.buffer->pointrect + snapshot_counter,588bPointerShapeChange);589}590else591{592HandleDriverChangesSeries(593pDesk,594rgn,595xoffset, yoffset,596bufdata.buffer->pointrect + oldCounter,597bufdata.buffer->pointrect + MAXCHANGES_BUF,598bPointerShapeChange);599600HandleDriverChangesSeries(601pDesk,602rgn,603xoffset, yoffset,604bufdata.buffer->pointrect,605bufdata.buffer->pointrect + snapshot_counter,606bPointerShapeChange);607}608609oldCounter = snapshot_counter;610}611612void vncVideoDriver::HandleDriverChangesSeries(613vncDesktop *pDesk,614vncRegion &rgn,615int xoffset,616int yoffset,617const CHANGES_RECORD *i,618const CHANGES_RECORD *last,619BOOL &bPointerShapeChange)620{621for (; i < last; i++)622{623// TODO bPointerShapeChange624625if (m_fHandleScreen2ScreenBlt && i->type == dmf_dfo_SCREEN_SCREEN)626{627// DPF(("CopyRect: (%d, %d, %d, %d)\n",628// i->rect.left,629// i->rect.top,630// i->rect.right,631// i->rect.bottom));632633RECT Rc;634Rc.left = i->rect.left + xoffset;635Rc.top = i->rect.top + yoffset;636Rc.right = i->rect.right + xoffset;637Rc.bottom = i->rect.bottom + yoffset;638639POINT Pt;640Pt.x = i->point.x + xoffset;641Pt.y = i->point.y + yoffset;642pDesk->CopyRect(Rc, Pt);643continue;644}645646if (i->type >= dmf_dfo_SCREEN_SCREEN && i->type <= dmf_dfo_TEXTOUT)647{648// DPF(("XRect: (%d, %d, %d, %d)\n",649// i->rect.left,650// i->rect.top,651// i->rect.right,652// i->rect.bottom));653rgn.AddRect(i->rect, xoffset, yoffset);654}655}656}657658VOID DebugPrint(PCHAR DebugMessage,659...)660{661va_list ap;662va_start(ap, DebugMessage);663TCHAR pb[256];664vsprintf(pb, DebugMessage, ap);665va_end(ap);666OutputDebugString(pb);667}668669670