现代远程桌面技术:ThinVNC的实现与应用

随着互联网技术的不断发展,远程桌面技术已经逐渐成为日常工作和生活中不可或缺的一部分。传统的VNC技术虽然稳定可靠,但在现代的Web环境中,希望能够有更加灵活和高效的解决方案。ThinVNC就是在这样的背景下应运而生的。它不仅继承了VNC技术的优点,还通过现代Web技术实现了全平台、全浏览器的支持。

ThinVNC并非传统意义上的VNC,因为它并没有实现AT&T的RFB协议。相反,它是构建在当今Web标准之上的,包括AJAXJSONHTML5。这使得ThinVNC能够无缝地集成到各种Web应用程序中,并且提供了开箱即用的跨浏览器和跨平台支持。

代码实现(第一部分)

在第一部分中,将探讨如何实现屏幕捕获。通常的做法是捕获整个桌面,但在这里,将单独捕获每个窗口,应用裁剪区域,并保存单独的位图以便于后续的比较和差异提取。

首先,需要枚举所有可见的顶层窗口:

type TWin = class(TObject) private Wnd : Hwnd; Rect : TRect; Pid : Cardinal; public constructor Create(AWnd:HWND;ARect:TRect;APid:Cardinal); end; function EnumWindowsProc(Wnd: HWnd; const obj:TList): Bool; export; stdcall; var ProcessId : Cardinal; R,R1 : TRect; Win : TWin; begin Result:=True; GetWindowThreadProcessId(Wnd,ProcessId); if IsWindowVisible(Wnd) and not IsIconic(wnd)then begin GetWindowRect(Wnd,R); IntersectRect(R1,R,Screen.DesktopRect); if not IsRectEmpty(R1) then begin win := TWin.Create(Wnd,R,ProcessId); obj.Add(win); end; end; end; procedure GetProcessWindowList(WinList:TList); begin WinList.Clear; EnumWindows(@EnumWindowsProc, Longint(WinList)); end;

希望保持一个窗口列表,包括它们的基本属性和位图,以便可以与新的窗口进行比较,并将差异发送给客户端。在这里将窗口列表合并到一个窗口镜像列表中:

type TWindowMirror = class private FIndex : Integer; FRgn : HRGN; FHandle : THandle; FBoundsRect : TRect; FProcessId : Integer; FImage : TBitmap; FDiffStreamList : TList; ... ... end;

接下来,将更新镜像列表:

procedure TMirrorManager.RefreshMirrorList(out OneMoved:Boolean); procedure GetProcessWindowList(WinList:TList); begin WinList.Clear; EnumWindows(@EnumWindowsProc, Longint(WinList)); end; var wl : TList; n : Integer; wm : TWindowMirror; begin OneMoved:=False; wl := TList.Create; try // Enumerates top windows GetProcessWindowList(wl); try for n := wl.Count - 1 downto 0 do begin // Looks for a cached window wm:=GetWindowMirror(FMirrorList,wl[n].Wnd); if assigned(wm) then begin if IsIconic(wl[n].Wnd) then wm.SetBoundsRect(Rect(0,0,0,0)) else wm.SetBoundsRect(wl[n].Rect); // Returns true when at least one window moved OneMoved:=OneMoved or (DateTimeToTimeStamp(Now-wm.FMoved).time

现在,进行捕获:

function TWindowMirror.Capture(ANewImage:TBitmap): Boolean; function BitBlt(DestDC: HDC; X, Y, Width, Height: Integer; SrcDC: HDC; XSrc, YSrc: Integer; Rop: DWORD): BOOL; begin // Capture only visible regions SelectClipRgn(DestDC,FRgn); result:=Windows.BitBlt(DestDC, X, Y, Width, Height, SrcDC, XSrc, YSrc, Rop); SelectClipRgn(DestDC,0); end; var DC : HDC; RasterOp,ExStyle: DWORD; begin RasterOp := SRCCOPY; ExStyle:=GetWindowLong(FHandle, GWL_EXSTYLE); if (ExStyle and WS_EX_LAYERED) = WS_EX_LAYERED then RasterOp := SRCCOPY or CAPTUREBLT; DC := GetDCEx(FHandle,0,DCX_WINDOW or DCX_NORESETATTRS or DCX_CACHE); try Result:=BitBlt(ANewImage.Canvas.Handle,0,0, Width(FBoundsRect),Height(FBoundsRect),DC,0,0, RasterOp) finally ReleaseDC(FHandle,DC); end; end;

现在已经捕获了所有可见区域,需要获取与之前捕获的位图的差异。通过循环遍历窗口,然后是它们的可见区域,最后计算发现位图差异的区域:

function TWindowMirror.CaptureDifferences(reset:boolean=false): Boolean; .... begin ... result:=Capture(TmpImage); if result then begin ... ra:=ExtractClippingRegions(Rect(0,0,TmpImage.Width,TmpImage.Height)); for n := 0 to Length(ra) - 1 do begin ra2:=GetDiffRects(FImage,TmpImage,ra[n]); for m := 0 to Length(ra2) - 1 do begin Jpg := TJpegImage.Create; ... CopyBmpToJpg(Jpg,TmpImage,ra2[m]); FDiffStreamList.Add(TImagePart.Create(rbmp,'jpeg')); Jpg.SaveToStream(FDiffStreamList[FDiffStreamList.Count-1].FStream); ... Bitblt(FImage.Canvas.Handle, ra2[m].Left,ra2[m].Top,Width(ra2[m]),Height(ra2[m]), TmpImage.Canvas.handle, rbmp.Left,ra2[m].Top,SRCCOPY); end; end; ... end;
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485