CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/external/source/vncdll/winvnc/VideoDriver.cpp
Views: 11780
1
// Copyright (C) 2005-2006 Lev Kazarkin. All Rights Reserved.
2
//
3
// TightVNC is free software; you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation; either version 2 of the License, or
6
// (at your option) any later version.
7
//
8
// This program is distributed in the hope that it will be useful,
9
// but WITHOUT ANY WARRANTY; without even the implied warranty of
10
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
// GNU General Public License for more details.
12
//
13
// You should have received a copy of the GNU General Public License
14
// along with this program; if not, write to the Free Software
15
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16
// USA.
17
//
18
// TightVNC distribution homepage on the Web: http://www.tightvnc.com/
19
20
#include "VideoDriver.h"
21
#include "vncDesktop.h"
22
23
char vncVideoDriver::szDriverString[] = "Mirage Driver";
24
char vncVideoDriver::szDriverStringAlt[] = "DemoForge Mirage Driver";
25
char vncVideoDriver::szMiniportName[] = "dfmirage";
26
27
#define MINIPORT_REGISTRY_PATH "SYSTEM\\CurrentControlSet\\Hardware Profiles\\Current\\System\\CurrentControlSet\\Services"
28
29
BOOL IsWinNT();
30
BOOL IsNtVer(ULONG mj, ULONG mn);
31
BOOL IsWinVerOrHigher(ULONG mj, ULONG mn);
32
33
34
vncVideoDriver::vncVideoDriver()
35
{
36
bufdata.buffer = NULL;
37
bufdata.Userbuffer = NULL;
38
m_fIsActive = false;
39
m_fDirectAccessInEffect = false;
40
m_fHandleScreen2ScreenBlt = false;
41
*m_devname= 0;
42
m_drv_ver_mj = 0;
43
m_drv_ver_mn = 0;
44
}
45
46
vncVideoDriver::~vncVideoDriver()
47
{
48
UnMapSharedbuffers();
49
Deactivate();
50
_ASSERTE(!m_fIsActive);
51
_ASSERTE(!m_fDirectAccessInEffect);
52
}
53
54
#define BYTE0(x) ((x) & 0xFF)
55
#define BYTE1(x) (((x) >> 8) & 0xFF)
56
#define BYTE2(x) (((x) >> 16) & 0xFF)
57
#define BYTE3(x) (((x) >> 24) & 0xFF)
58
59
BOOL vncVideoDriver::CheckVersion()
60
{
61
_ASSERTE(IsWinNT());
62
63
HDC l_gdc= ::CreateDC(m_devname, NULL, NULL, NULL);
64
if (!l_gdc)
65
{
66
return FALSE;
67
}
68
69
Esc_dmf_Qvi_IN qvi_in;
70
qvi_in.cbSize = sizeof(qvi_in);
71
72
qvi_in.app_actual_version = DMF_PROTO_VER_CURRENT;
73
qvi_in.display_minreq_version = DMF_PROTO_VER_MINCOMPAT;
74
qvi_in.connect_options = 0;
75
76
Esc_dmf_Qvi_OUT qvi_out;
77
qvi_out.cbSize = sizeof(qvi_out);
78
79
int drvCr = ExtEscape(
80
l_gdc,
81
ESC_QVI,
82
sizeof(qvi_in), (LPSTR) &qvi_in,
83
sizeof(qvi_out), (LPSTR) &qvi_out);
84
DeleteDC(l_gdc);
85
86
if (drvCr == 0)
87
{
88
return FALSE;
89
}
90
91
if (drvCr < 0)
92
{
93
return FALSE;
94
}
95
96
m_drv_ver_mj = BYTE3(qvi_out.display_actual_version);
97
m_drv_ver_mn = BYTE2(qvi_out.display_actual_version);
98
99
return TRUE;
100
}
101
102
BOOL vncVideoDriver::MapSharedbuffers(BOOL fForDirectScreenAccess)
103
{
104
_ASSERTE(!m_fIsActive);
105
_ASSERTE(!m_fDirectAccessInEffect);
106
_ASSERTE(IsWinNT());
107
108
HDC l_gdc= ::CreateDC(m_devname, NULL, NULL, NULL);
109
if (!l_gdc)
110
{
111
return FALSE;
112
}
113
114
oldCounter = 0;
115
int drvCr = ExtEscape(
116
l_gdc,
117
MAP1,
118
0, NULL,
119
sizeof(GETCHANGESBUF), (LPSTR) &bufdata);
120
DeleteDC(l_gdc);
121
122
if (drvCr <= 0)
123
{
124
return FALSE;
125
}
126
m_fIsActive = true;
127
if (fForDirectScreenAccess)
128
{
129
if (!bufdata.Userbuffer)
130
{
131
return FALSE;
132
}
133
m_fDirectAccessInEffect = true;
134
}
135
136
// Screen2Screen support added in Mirage ver 1.2
137
m_fHandleScreen2ScreenBlt = (m_drv_ver_mj > 1) || (m_drv_ver_mj == 1 && m_drv_ver_mn >= 2);
138
139
return TRUE;
140
}
141
142
BOOL vncVideoDriver::TestMapped()
143
{
144
_ASSERTE(IsWinNT());
145
146
TCHAR *pDevName;
147
if (IsWinVerOrHigher(5, 0))
148
{
149
DISPLAY_DEVICE dd;
150
INT devNum = 0;
151
if (!LookupVideoDeviceAlt(szDriverString, szDriverStringAlt, devNum, &dd))
152
return FALSE;
153
pDevName = (TCHAR *)dd.DeviceName;
154
}
155
else
156
{
157
pDevName = "DISPLAY";
158
}
159
160
HDC l_ddc = ::CreateDC(pDevName, NULL, NULL, NULL);
161
if (l_ddc)
162
{
163
BOOL b = ExtEscape(l_ddc, TESTMAPPED, 0, NULL, 0, NULL);
164
DeleteDC(l_ddc);
165
return b;
166
}
167
return FALSE;
168
}
169
170
void vncVideoDriver::UnMapSharedbuffers()
171
{
172
_ASSERTE(IsWinNT());
173
174
int DrvCr = 0;
175
if (m_devname[0])
176
{
177
_ASSERTE(m_fIsActive);
178
_ASSERTE(bufdata.buffer);
179
_ASSERTE(!m_fDirectAccessInEffect || bufdata.Userbuffer);
180
181
HDC l_gdc= ::CreateDC(m_devname, NULL, NULL, NULL);
182
if (l_gdc)
183
{
184
DrvCr = ExtEscape(
185
l_gdc,
186
UNMAP1,
187
sizeof(GETCHANGESBUF), (LPSTR) &bufdata,
188
0, NULL);
189
DeleteDC(l_gdc);
190
191
_ASSERTE(DrvCr > 0);
192
}
193
}
194
// 0 return value is unlikely for Mirage because its DC is independent
195
// from the reference device;
196
// this happens with Quasar if its mode was changed externally.
197
// nothing is particularly bad with it.
198
199
if (DrvCr <= 0)
200
{
201
if (bufdata.buffer)
202
{
203
BOOL br = UnmapViewOfFile(bufdata.buffer);
204
}
205
if (bufdata.Userbuffer)
206
{
207
BOOL br = UnmapViewOfFile(bufdata.Userbuffer);
208
}
209
}
210
m_fIsActive = false;
211
m_fDirectAccessInEffect = false;
212
m_fHandleScreen2ScreenBlt = false;
213
}
214
215
template <class TpFn>
216
HINSTANCE LoadNImport(LPCTSTR szDllName, LPCTSTR szFName, TpFn &pfn)
217
{
218
HINSTANCE hDll = LoadLibrary(szDllName);
219
if (hDll)
220
{
221
pfn = (TpFn)GetProcAddress(hDll, szFName);
222
if (pfn)
223
return hDll;
224
FreeLibrary(hDll);
225
}
226
return NULL;
227
}
228
229
//BOOL vncVideoDriver::LookupVideoDevice(LPCTSTR szDeviceString, INT &devNum, DISPLAY_DEVICE *pDd)
230
BOOL vncVideoDriver::LookupVideoDeviceAlt(
231
LPCTSTR szDevStr,
232
LPCTSTR szDevStrAlt,
233
INT &devNum,
234
DISPLAY_DEVICE *pDd)
235
{
236
_ASSERTE(IsWinVerOrHigher(5, 0));
237
238
pEnumDisplayDevices pd = NULL;
239
HINSTANCE hInstUser32 = LoadNImport("User32.DLL", "EnumDisplayDevicesA", pd);
240
if (!hInstUser32) return FALSE;
241
242
ZeroMemory(pDd, sizeof(DISPLAY_DEVICE));
243
pDd->cb = sizeof(DISPLAY_DEVICE);
244
BOOL result;
245
while (result = (*pd)(NULL,devNum, pDd, 0))
246
{
247
if (strcmp((const char *)pDd->DeviceString, szDevStr) == 0 ||
248
szDevStrAlt && strcmp((const char *)pDd->DeviceString, szDevStrAlt) == 0)
249
{
250
break;
251
}
252
devNum++;
253
}
254
255
FreeLibrary(hInstUser32);
256
return result;
257
}
258
259
HKEY vncVideoDriver::CreateDeviceKey(LPCTSTR szMpName)
260
{
261
HKEY hKeyProfileMirror = (HKEY)0;
262
if (RegCreateKey(
263
HKEY_LOCAL_MACHINE,
264
(MINIPORT_REGISTRY_PATH),
265
&hKeyProfileMirror) != ERROR_SUCCESS)
266
{
267
return FALSE;
268
}
269
HKEY hKeyProfileMp = (HKEY)0;
270
LONG cr = RegCreateKey(
271
hKeyProfileMirror,
272
szMpName,
273
&hKeyProfileMp);
274
RegCloseKey(hKeyProfileMirror);
275
if (cr != ERROR_SUCCESS)
276
{
277
return FALSE;
278
}
279
HKEY hKeyDevice = (HKEY)0;
280
if (RegCreateKey(
281
hKeyProfileMp,
282
("DEVICE0"),
283
&hKeyDevice) != ERROR_SUCCESS)
284
{
285
286
}
287
RegCloseKey(hKeyProfileMp);
288
return hKeyDevice;
289
}
290
291
BOOL vncVideoDriver::Activate(
292
BOOL fForDirectAccess,
293
const RECT *prcltarget)
294
{
295
_ASSERTE(IsWinNT());
296
297
if (IsWinVerOrHigher(5, 0))
298
{
299
return Activate_NT50(fForDirectAccess, prcltarget);
300
}
301
else
302
{
303
// NOTE: prcltarget is just a SourceDisplayRect.
304
// there is only 1 possibility on NT4, so safely ignore it
305
return Activate_NT46(fForDirectAccess);
306
}
307
}
308
309
void vncVideoDriver::Deactivate()
310
{
311
_ASSERTE(IsWinNT());
312
313
if (IsWinVerOrHigher(5, 0))
314
{
315
Deactivate_NT50();
316
}
317
else
318
{
319
Deactivate_NT46();
320
}
321
}
322
323
BOOL vncVideoDriver::Activate_NT50(
324
BOOL fForDirectAccess,
325
const RECT *prcltarget)
326
{
327
HDESK hdeskInput;
328
HDESK hdeskCurrent;
329
330
DISPLAY_DEVICE dd;
331
INT devNum = 0;
332
if (!LookupVideoDeviceAlt(szDriverString, szDriverStringAlt, devNum, &dd))
333
{
334
return FALSE;
335
}
336
337
DEVMODE devmode;
338
FillMemory(&devmode, sizeof(DEVMODE), 0);
339
devmode.dmSize = sizeof(DEVMODE);
340
devmode.dmDriverExtra = 0;
341
BOOL change = EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devmode);
342
devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
343
if (prcltarget)
344
{
345
// we always have to set position or
346
// a stale position info in registry would come into effect.
347
devmode.dmFields |= DM_POSITION;
348
devmode.dmPosition.x = prcltarget->left;
349
devmode.dmPosition.y = prcltarget->top;
350
351
devmode.dmPelsWidth = prcltarget->right - prcltarget->left;
352
devmode.dmPelsHeight = prcltarget->bottom - prcltarget->top;
353
}
354
355
devmode.dmDeviceName[0] = '\0';
356
357
HKEY hKeyDevice = CreateDeviceKey(szMiniportName);
358
if (hKeyDevice == NULL)
359
return FALSE;
360
361
// TightVNC does not use these features
362
RegDeleteValue(hKeyDevice, ("Screen.ForcedBpp"));
363
RegDeleteValue(hKeyDevice, ("Pointer.Enabled"));
364
365
DWORD dwVal = fForDirectAccess ? 3 : 0;
366
// NOTE that old driver ignores it and mapping is always ON with it
367
if (RegSetValueEx(
368
hKeyDevice,
369
("Cap.DfbBackingMode"),
370
0,
371
REG_DWORD,
372
(unsigned char *)&dwVal,
373
4) != ERROR_SUCCESS)
374
{
375
return FALSE;
376
}
377
378
dwVal = 1;
379
if (RegSetValueEx(
380
hKeyDevice,
381
("Order.BltCopyBits.Enabled"),
382
0,
383
REG_DWORD,
384
(unsigned char *)&dwVal,
385
4) != ERROR_SUCCESS)
386
{
387
return FALSE;
388
}
389
390
dwVal = 1;
391
if (RegSetValueEx(
392
hKeyDevice,
393
("Attach.ToDesktop"),
394
0,
395
REG_DWORD,
396
(unsigned char *)&dwVal,
397
4) != ERROR_SUCCESS)
398
{
399
return FALSE;
400
}
401
402
pChangeDisplaySettingsEx pCDS = NULL;
403
HINSTANCE hInstUser32 = LoadNImport("User32.DLL", "ChangeDisplaySettingsExA", pCDS);
404
if (!hInstUser32) return FALSE;
405
406
// Save the current desktop
407
hdeskCurrent = GetThreadDesktop(GetCurrentThreadId());
408
if (hdeskCurrent != NULL)
409
{
410
hdeskInput = OpenInputDesktop(0, FALSE, MAXIMUM_ALLOWED);
411
if (hdeskInput != NULL)
412
SetThreadDesktop(hdeskInput);
413
}
414
// 24 bpp screen mode is MUNGED to 32 bpp.
415
// the underlying buffer format must be 32 bpp.
416
// see vncDesktop::ThunkBitmapInfo()
417
if (devmode.dmBitsPerPel==24) devmode.dmBitsPerPel = 32;
418
LONG cr = (*pCDS)(
419
(TCHAR *)dd.DeviceName,
420
&devmode,
421
NULL,
422
CDS_UPDATEREGISTRY,NULL);
423
424
strcpy(m_devname, (const char *)dd.DeviceName);
425
426
// Reset desktop
427
SetThreadDesktop(hdeskCurrent);
428
// Close the input desktop
429
CloseDesktop(hdeskInput);
430
RegCloseKey(hKeyDevice);
431
FreeLibrary(hInstUser32);
432
433
return TRUE;
434
}
435
436
BOOL vncVideoDriver::Activate_NT46(BOOL fForDirectAccess)
437
{
438
HKEY hKeyDevice = CreateDeviceKey(szMiniportName);
439
if (hKeyDevice == NULL)
440
return FALSE;
441
442
// TightVNC does not use these features
443
RegDeleteValue(hKeyDevice, ("Screen.ForcedBpp"));
444
RegDeleteValue(hKeyDevice, ("Pointer.Enabled"));
445
446
DWORD dwVal = fForDirectAccess ? 3 : 0;
447
// NOTE that old driver ignores it and mapping is always ON with it
448
if (RegSetValueEx(
449
hKeyDevice,
450
("Cap.DfbBackingMode"),
451
0,
452
REG_DWORD,
453
(unsigned char *)&dwVal,
454
4) != ERROR_SUCCESS)
455
{
456
return FALSE;
457
}
458
459
dwVal = 1;
460
if (RegSetValueEx(
461
hKeyDevice,
462
("Order.BltCopyBits.Enabled"),
463
0,
464
REG_DWORD,
465
(unsigned char *)&dwVal,
466
4) != ERROR_SUCCESS)
467
{
468
return FALSE;
469
}
470
471
// NOTE: we cannot truly load the driver
472
// but ChangeDisplaySettings makes PDEV to reload
473
// and thus new settings come into effect
474
475
// TODO
476
477
strcpy(m_devname, "DISPLAY");
478
479
RegCloseKey(hKeyDevice);
480
return TRUE;
481
}
482
483
void vncVideoDriver::Deactivate_NT50()
484
{
485
HDESK hdeskInput;
486
HDESK hdeskCurrent;
487
488
// it is important to us to be able to deactivate
489
// even what we have never activated. thats why we look it up, all over
490
// if (!m_devname[0])
491
// return;
492
// ... and forget the name
493
*m_devname = 0;
494
495
DISPLAY_DEVICE dd;
496
INT devNum = 0;
497
if (!LookupVideoDeviceAlt(szDriverString, szDriverStringAlt, devNum, &dd))
498
{
499
return;
500
}
501
502
DEVMODE devmode;
503
FillMemory(&devmode, sizeof(DEVMODE), 0);
504
devmode.dmSize = sizeof(DEVMODE);
505
devmode.dmDriverExtra = 0;
506
BOOL change = EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devmode);
507
devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
508
devmode.dmDeviceName[0] = '\0';
509
510
HKEY hKeyDevice = CreateDeviceKey(szMiniportName);
511
if (hKeyDevice == NULL)
512
return;
513
514
DWORD one = 0;
515
if (RegSetValueEx(hKeyDevice,("Attach.ToDesktop"), 0, REG_DWORD, (unsigned char *)&one,4) != ERROR_SUCCESS)
516
{
517
518
}
519
520
// reverting to default behavior
521
RegDeleteValue(hKeyDevice, ("Cap.DfbBackingMode"));
522
RegDeleteValue(hKeyDevice, ("Order.BltCopyBits.Enabled"));
523
524
pChangeDisplaySettingsEx pCDS = NULL;
525
HINSTANCE hInstUser32 = LoadNImport("User32.DLL", "ChangeDisplaySettingsExA", pCDS);
526
if (!hInstUser32) return;
527
528
// Save the current desktop
529
hdeskCurrent = GetThreadDesktop(GetCurrentThreadId());
530
if (hdeskCurrent != NULL)
531
{
532
hdeskInput = OpenInputDesktop(0, FALSE, MAXIMUM_ALLOWED);
533
if (hdeskInput != NULL)
534
SetThreadDesktop(hdeskInput);
535
}
536
// 24 bpp screen mode is MUNGED to 32 bpp. see vncDesktop::ThunkBitmapInfo()
537
if (devmode.dmBitsPerPel==24) devmode.dmBitsPerPel = 32;
538
539
// Add 'Default.*' settings to the registry under above hKeyProfile\mirror\device
540
(*pCDS)((TCHAR *)dd.DeviceName, &devmode, NULL, CDS_UPDATEREGISTRY, NULL);
541
542
// Reset desktop
543
SetThreadDesktop(hdeskCurrent);
544
// Close the input desktop
545
CloseDesktop(hdeskInput);
546
RegCloseKey(hKeyDevice);
547
FreeLibrary(hInstUser32);
548
}
549
550
void vncVideoDriver::Deactivate_NT46()
551
{
552
// ... and forget the name
553
*m_devname = 0;
554
555
HKEY hKeyDevice = CreateDeviceKey(szMiniportName);
556
if (hKeyDevice == NULL)
557
return;
558
559
// reverting to default behavior
560
RegDeleteValue(hKeyDevice, ("Cap.DfbBackingMode"));
561
562
// RegDeleteValue(hKeyDevice, ("Order.BltCopyBits.Enabled"));
563
// TODO: remove "Order.BltCopyBits.Enabled"
564
// now we don't touch this important option
565
// because we dont apply the changed values
566
567
RegCloseKey(hKeyDevice);
568
}
569
570
void vncVideoDriver::HandleDriverChanges(
571
vncDesktop *pDesk,
572
vncRegion &rgn,
573
int xoffset,
574
int yoffset,
575
BOOL &bPointerShapeChange)
576
{
577
ULONG snapshot_counter = bufdata.buffer->counter;
578
if (oldCounter == snapshot_counter)
579
return;
580
581
if (oldCounter < snapshot_counter)
582
{
583
HandleDriverChangesSeries(
584
pDesk,
585
rgn,
586
xoffset, yoffset,
587
bufdata.buffer->pointrect + oldCounter,
588
bufdata.buffer->pointrect + snapshot_counter,
589
bPointerShapeChange);
590
}
591
else
592
{
593
HandleDriverChangesSeries(
594
pDesk,
595
rgn,
596
xoffset, yoffset,
597
bufdata.buffer->pointrect + oldCounter,
598
bufdata.buffer->pointrect + MAXCHANGES_BUF,
599
bPointerShapeChange);
600
601
HandleDriverChangesSeries(
602
pDesk,
603
rgn,
604
xoffset, yoffset,
605
bufdata.buffer->pointrect,
606
bufdata.buffer->pointrect + snapshot_counter,
607
bPointerShapeChange);
608
}
609
610
oldCounter = snapshot_counter;
611
}
612
613
void vncVideoDriver::HandleDriverChangesSeries(
614
vncDesktop *pDesk,
615
vncRegion &rgn,
616
int xoffset,
617
int yoffset,
618
const CHANGES_RECORD *i,
619
const CHANGES_RECORD *last,
620
BOOL &bPointerShapeChange)
621
{
622
for (; i < last; i++)
623
{
624
// TODO bPointerShapeChange
625
626
if (m_fHandleScreen2ScreenBlt && i->type == dmf_dfo_SCREEN_SCREEN)
627
{
628
// DPF(("CopyRect: (%d, %d, %d, %d)\n",
629
// i->rect.left,
630
// i->rect.top,
631
// i->rect.right,
632
// i->rect.bottom));
633
634
RECT Rc;
635
Rc.left = i->rect.left + xoffset;
636
Rc.top = i->rect.top + yoffset;
637
Rc.right = i->rect.right + xoffset;
638
Rc.bottom = i->rect.bottom + yoffset;
639
640
POINT Pt;
641
Pt.x = i->point.x + xoffset;
642
Pt.y = i->point.y + yoffset;
643
pDesk->CopyRect(Rc, Pt);
644
continue;
645
}
646
647
if (i->type >= dmf_dfo_SCREEN_SCREEN && i->type <= dmf_dfo_TEXTOUT)
648
{
649
// DPF(("XRect: (%d, %d, %d, %d)\n",
650
// i->rect.left,
651
// i->rect.top,
652
// i->rect.right,
653
// i->rect.bottom));
654
rgn.AddRect(i->rect, xoffset, yoffset);
655
}
656
}
657
}
658
659
VOID DebugPrint(PCHAR DebugMessage,
660
...)
661
{
662
va_list ap;
663
va_start(ap, DebugMessage);
664
TCHAR pb[256];
665
vsprintf(pb, DebugMessage, ap);
666
va_end(ap);
667
OutputDebugString(pb);
668
}
669
670