翻译《The Old New Thing》- Taxes: Remote Desktop Connection and painting

Taxes: Remote Desktop Connection and painting - The Old New Thingicon-default.png?t=N7T8https://devblogs.microsoft.com/oldnewthing/20060103-12/?p=32793

Raymond Chen 2006年01月03日


开发成本:远程桌面连接和绘制

        当用户通过远程桌面连接进行连接时,视频操作会通过网络传输到客户端进行显示。由于网络的延迟较高,且带宽远远低于本地PCI或AGP总线,您需要适应屏幕绘制成本的变化。

        如果您在屏幕上绘制一条线,那么“绘制线条”的命令会通过网络发送到客户端。如果您绘制文本,会发送一个“绘制文本”的命令(以及要绘制的文本)。到目前为止,一切都很好。

        但是,如果您将一个位图复制到屏幕上,那么整个位图都需要通过网络传输。

        让我们编写一个示例程序来说明这一点。从我们的新草稿程序开始,并进行以下更改:

void Window::Register()
{WNDCLASS wc;wc.style = CS_VREDRAW | CS_HREDRAW;wc.lpfnWndProc = Window::s_WndProc;...
}class RootWindow : public Window
{
public:virtual LPCTSTR ClassName() { return TEXT("Scratch"); }static RootWindow *Create();
protected:LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);LRESULT OnCreate();void PaintContent(PAINTSTRUCT *pps);void Draw(HDC hdc, PAINTSTRUCT *pps);
private:HWND m_hwndChild;
};void RootWindow::Draw(HDC hdc, PAINTSTRUCT *pps)
{FillRect(hdc, &pps->rcPaint, (HBRUSH)(COLOR_WINDOW + 1));RECT rc;GetClientRect(m_hwnd, &rc);for (int i = -10; i < 10; i++){TextOut(hdc, 0, i * 15 + rc.bottom / 2, TEXT("Blah blah"), 9);}
}void RootWindow::PaintContent(PAINTSTRUCT *pps)
{Draw(pps->hdc, pps);
}LRESULT RootWindow::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{switch (uMsg){...case WM_ERASEBKGND: return 1;...}
}

        这里有一个奇怪的分工;PaintContent方法实际上并不执行任何绘制操作,而是将绘制任务委托给Draw方法来完成。(您很快就会明白原因。)

        确保启用了“拖动时显示窗口内容”的选项,然后运行这个程序并垂直调整其大小。

        哎呀,多么难看的闪烁。

        我们通过传统的双缓冲技术来修复这个问题。

void RootWindow::PaintContent(PAINTSTRUCT *pps)
{if (!IsRectEmpty(&pps->rcPaint)){HDC hdc = CreateCompatibleDC(pps->hdc);if (hdc){int x = pps->rcPaint.left;int y = pps->rcPaint.top;int cx = pps->rcPaint.right - pps->rcPaint.left;int cy = pps->rcPaint.bottom - pps->rcPaint.top;HBITMAP hbm = CreateCompatibleBitmap(pps->hdc, cx, cy);if (hbm){HBITMAP hbmPrev = SelectBitmap(hdc, hbm);SetWindowOrgEx(hdc, x, y, NULL);Draw(hdc, pps);BitBlt(pps->hdc, x, y, cx, cy, hdc, x, y, SRCCOPY);SelectObject(hdc, hbmPrev);DeleteObject(hbm);}DeleteDC(hdc);}}
}

        我们的新PaintContent方法创建了一个离屏位图,并请求Draw方法将其绘制到其中。一旦完成,结果就会一次性地复制到屏幕上,从而避免了闪烁。

        如果您运行这个程序,您会发现它在调整大小时非常平滑。

        现在,通过远程桌面连接连接到计算机,然后再次运行它。

        由于远程桌面连接禁用了“拖动时显示窗口内容”的选项,您不能通过调整大小来触发重绘,而是应该将程序最大化和恢复几次。

        请注意,在您最大化窗口时,窗口调整大小之前会有一段较长的延迟。

        这是因为我们在BitBlt调用中,通过远程桌面连接传输了一个巨大的位图。

        回到PaintContent方法的旧版本,即只调用Draw的那个版本,并通过远程桌面连接运行它。

        啊,这个快多了。

        这是因为简化的版本不会通过远程桌面连接传输一个巨大的位图;它只是发送了二十个TextOut调用,这些调用涉及一个相当短的文本字符串。

        这些调用所占用的带宽远少于一个1024×768的位图。

        我们有一种方法在远程桌面连接上更快,另一种方法在本地运行时更快。

        我们应该使用哪种方法?

        我们两者都用,根据程序是否通过远程桌面连接运行来选择我们的绘图方法。

void RootWindow::PaintContent(PAINTSTRUCT *pps)
{if (GetSystemMetrics(SM_REMOTESESSION)){Draw(pps->hdc, pps);}else if (!IsRectEmpty(&pps->rcPaint)){...如前所述...}
}

        现在我们得到了最佳效果。

        当在本地运行时,我们使用双缓冲绘图,这样可以无闪烁地绘制,但当通过远程桌面连接运行时,我们使用简单的Draw方法直接绘制到屏幕上,而不是绘制到离屏位图。

        这是一个适应远程桌面连接的非常简单的例子。

        在一个更复杂的世界里,您可能需要根据两种绘图风格的需要,处理更复杂的数据结构,或者您可能需要根据程序是否通过远程桌面连接运行来开启或关闭与绘图相关的后台活动。

        由于用户可以动态地连接和断开连接,您不能仅仅假设程序启动时远程桌面连接的状态将一直保持不变。

        下次我们将看到如何适应一个不断变化的环境。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/701848.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Centos 7.9 安装 tigervnc-server

环境&#xff1a;当前使用的 Centos 7.9 的光盘作为的本地源&#xff0c;或使用离线rpm包。 1 检查是否已安装 tigervnc [rootlocalhost /]# rpm -q tigervnc tigervnc-server 未安装软件包 tigervnc tigervnc-server-1.8.0-21.el7.x86_64 如果安装过卸掉 卸载: rpm -e [ro…

机器学习 - 集成学习算法介绍

集成学习的定义 集成学习&#xff08;Ensemble Learning&#xff09;是一种通过组合多个模型来提升预测性能的技术。简单来说&#xff0c;它就像是在开会时听取多人的意见&#xff0c;而不是只依赖一个人的观点&#xff0c;从而做出更准确的决策。 1. Bagging&#xff08;Boo…

4种现象表明你的血糖控制良好!

如果你出现以下4种现象&#xff0c;恭喜你&#xff0c;说明你的血糖控制的不错&#xff0c;需要继续坚持。 1.饥饿感减少&#xff0c;我们的脏腑能够吸收血液中的糖分了&#xff0c;就用不着饿了。&#xff0c;血液中的糖能够得到充分的利用&#xff0c;血糖自然降下去。 2.体…

队列的讲解

队列的概念 队列:只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表&#xff0c;队列具有先进先出FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头 一端进另一端出 也就是可以做到&#xff0c;先…

单调栈练习

最大矩形面积 如果栈为空&#xff0c;或者新的元素是大于栈顶元素的&#xff0c;那么新来的元素不会破坏栈的单调性&#xff0c;那么就把这个柱子入栈。 特别注意&#xff1a;这里的s.empty()和s.top().height < a不能调换顺序&#xff0c;包括后面的判断也要先判断栈是否为…

iOS 创建pch文件

1.参考链接&#xff08;xcode8添加方法&#xff0c;之前的跟这个差不多&#xff09;&#xff1a; 参考链接 2.自我总结&#xff1a; &#xff08;1&#xff09;创建pch文件: 注意点&#xff1a;1&#xff09;注意选中所有的targets&#xff08;看图明义&#xff09; 2&…

基于java 自定义注解Annotation设计简单ORM框架——进阶篇

目录 引言实例新建两个注解标注实体类拼接sql语句 总结 引言 一般Java规范编程&#xff08;只是一种习惯&#xff0c;而不是强制&#xff09;中&#xff0c;变量的命名方式一般采用驼峰式命名。比如userName&#xff0c;userImage。但是在数据库中一般不会采用驼峰式&#xff…

如何在 Ubuntu 12.10 上使用 Python 创建 Nagios 插件

介绍 Python 是一种在 Linux 上默认可用的流行命令处理器。 我们之前已经介绍过如何在 Ubuntu 12.10 x64 上安装 Nagios 监控服务器。 这一次&#xff0c;我们将扩展这个想法&#xff0c;使用 Python 创建 Nagios 插件。 这些插件将在客户 VPS 上运行&#xff0c;并通过 NR…

利用KMeans进行遥感NDWI进行聚类分割

&#xff08;1&#xff09;解释 KMeans算法是一种非监督式的聚类算法&#xff0c;于1967年由J. MacQueen提出&#xff0c;聚类的依靠是欧式距离&#xff0c;其核心思想就是将样本划分为几个类别&#xff0c;类里面的数据与类中心的距离最小。类的标签采用类里面样本的均值。 这…

Android Compose四: 常用的组件 Text

Text Composable fun Text(text: String, //用于设置显示文本modifier: Modifier Modifier, //设置形状大小点击事件等color: Color Color.Unspecified, //fontSize: TextUnit TextUnit.Unspecified,fontStyle: FontStyle? null,fontWeight: FontW…

动态规划-两个数组的dp问题3

文章目录 1. 两个字符串的最小ASCII删除和&#xff08;712&#xff09;2. 最长重复子数组&#xff08;718&#xff09; 1. 两个字符串的最小ASCII删除和&#xff08;712&#xff09; 题目描述&#xff1a; 状态表示&#xff1a; 根据经验以及题目要求&#xff0c;建立二维数…

数据结构与算法学习笔记三---栈和队列

目录 前言 一、栈 1.栈的表示和实现 1.栈的顺序存储表示和实现 1.C语言实现 2.C实现 2.栈的链式存储表示和实现 1.C语言实现 2.C实现 2.栈的应用 1.数制转换 二、队列 1.栈队列的表示和实现 1.顺序队列的表示和实现 2.链队列的表示和实现 2.循环队列 前言 这篇文…