模态窗口其实就是在当前窗口调用系统的消息循环,响应用户的操作,将相关的消息发送到对应的窗口(转)

上周准备在公司内部转岗,面了3个部门windows客户端相关的工作,最终拿到3个Offer,主要涉及C++和Windows两大块内容,C++的题目基本都答上了,Windows一直都是我的弱项,在这里记录一下Windows相关的题目。有些答不上的问题就没列出来,还有些问题忘了,下面的答案有些大部分是我自己的理解,有些是直接从网上copy的,有问题大家可以讨论。

1:GetMessage和PeekMessage的区别?

GetMessage:获取消息队列中的一个消息,存入MSG中,并从消息队列中移除,如果消息队列中没有消息就会阻塞;

PeekMessage:查看消息,有消息,就将数据存入MSG结构中,没有消息就返回FALSE,不会阻塞,但如果没有更新区,可以移除WM_PAINT消息,还可以通过最后一个参数来决定是否从队列中移除查看的消息;

2:SendMessage和PostMessage的区别?怎么跨线程发消息?怎么跨进程发消息?SendMessage在进程间发消息要注意什么?SendMessage能将消息发送到消息队列吗?PostMessage可以在进程间发消息吗?两个线程互相SendMessage会出问题吗?

SendMessage:将一个消息发送到指定窗口的窗口过程中,等窗口过程执行完了再返回;

PostMessage:将消息发送到指定窗口所在线程的消息队列中,直接返回,消息是否被处理完全不知道;

SendMessage直接调用窗口过程,那它是否可以将消息发送到发送到线程的消息队列中呢?

可以啊,比如发送一个WM_PAINT消息,这是一个队列消息,只有存在无效区域的情况下,才会处理WM_PAINT消息;

线程间SendMessage,由于它基本就是调用指定窗口的窗口过程,当跨线程发消息的时候,无法调用指定窗口的窗口过程,在跨线程发送;

消息的时候,发送线程会先挂起,由系统线程将消息发送到接收线程的另一个队列中,并设置QS_SENDMESSAGE标志,当系统检测到这个标志后,就会处理这个队列的消息,当这个消息被处理之后,调用SendMessage的线程就会被唤醒,就继续执行。

SendMessage是可以跨进程发消息的,通过FindWindow找到对方进程的窗口句柄,发一个消息过去就行了,由于两个进程间的内存是完全独立的,不能发指针,如果要发数据,就用WM_COPYDATA。

PostMessage可以在进程间发消息,但不能结合WM_COPYDATA使用,WM_COPYDATA通过内存映射在进程间传递数据,PostMessage后映射文件的句柄就无效了。

两个线程互相SendMessage可能会导致死锁,A线程锁住一个资源,向B线程发一个消息,A线程挂起,这时如果B线程在处理A线程的消息需要A线程锁住的资源,A由于发给B的消息还没有处理完就一直不能返回,锁也没有打开,B线程又用不了,消息也就处理不完,结果就死锁了。

3:Windows是怎么实现窗口刷新的?怎么实现窗口的立即刷新?

Update Region不为空时,系统就会自动产生WM_PAINT消息,通过InvalidateRect和InvalidateRgn可把指定的区域加到窗口的Update Region中,通过处理WM_PAINT消息来实现窗口的刷新。 系统为什么不在调用Invalidate时发送WM_PAINT消息呢?又为什么非要等应用消息队列为空时才发送WM_PAINT消息呢?这是因为系统把在窗口中的绘制操作当作一种低优先级的操作,于是尽可能地推后做。不过这样也有利于提高绘制的效率:两个WM_PAINT消息之间通过InvalidateRect和InvaliateRgn使之失效的区域就会被累加起来,然后在一个WM_PAINT消息中一次得到更新,不仅能避免多次重复地更新同一区域,也优化了应用的更新操作。

如果窗口更新的区域不为空,UpdateWindow函数通过发送一个WM_PAINT消息来更新指定窗口的客户区。函数绕过应用程序的消息队列,直接发送WM_PAINT消息给指定窗口的窗口过程,如果更新区域为空,则不发送消息。

WM_PAINT一般在消息队列中没有消息的时候才处理,有时候我们需要立即刷新窗口,那么就需要UpdateWindow函数了,直接绕过消息循环,只要更新区域不为空,将WM_PAINT消息直接发送到指定窗口过程即可。

Invalidate(hwnd); //将窗口设为不可用,导致更新区域不为空

UpdateWindow(hwnd); //立即刷新窗口

4:Windows消息循环有哪几个函数,各自的作用是什么?消息循环是怎么退出的?

while(GetMessage(&msg, NULL, 0, 0)) //获取一个消息,成功后会放在msg中。

{

TranslateMessage(&msg); //消息进行必要的处理转换。

DispatchMessage(&msg); //调用WinProc,将msg的各项信息传递给WinProc
}

当GetMessage获取到的消息是WM_QUIT,返回的就是FALSE,while循环就退出了,消息循环也就终止了。

5:句柄是什么?

句柄就是一个整数,Windows为每一个控件指定了一个唯一的整数,通过这个整数和相关函数操作控件。

6:Windows实现线程间同步有哪些方法?实现进程间同步又有哪些方法?读写锁的实现原理是什么?

1:volatile

2:关键段

3:旋转锁

4:读写锁

5:事件对象

6:信号量

7:互斥量

只要是内核对象,就能用于进程间的同步,内核对象不属于任何进程,由系统管理。

读写锁实际是一种特殊的自旋锁,它把对共享资源的访问者划分成读者和写者,读者只对共享资源进行读访问,写者则需要对共享资源进行写操作。这种锁相对于自旋锁而言,能提高并发性,因为在多处理器系统中,它允许同时有多个读者来访问共享资源,最大可能的读者数为实际的逻辑CPU数。写者是排他性的,一个读写锁同时只能有一个写者或多个读者(与CPU数相关),但不能同时既有读者又有写者。我觉得他其实就是对关键段和内核事件对象的封装。写的时候独占,读的时候共享。

7:模态窗口的实现原理?模态窗口会导致崩溃吗?

模态窗口其实就是在当前窗口调用系统的消息循环,响应用户的操作,将相关的消息发送到对应的窗口。将父窗口设为不可用,即不能响应用户的操作,在关闭当前窗口的时候,将父窗口设为可用,并退出消息循环。

可能导致窗口崩溃,模态窗口显示的时候,除了父窗口不可用之外,其他的窗口都是可用的,如果需要的一个资源在别的地方被释放了,而在模态窗口中使用的时候,没有判断可能就会导致崩溃。

8:你了解沙箱,UAC相关的知识吗?

不了解

9:怎么实现线程间发消息?线程的消息队列默认会创建吗?

SendMessage可以再线程间发消息,PostThreadMessage通过线程ID可以在线程间发消息,将消息发送到指定线程的消息队列中。线程的消息队列默认是不会创建的,因为线程的消息队列并不是必须的。通过ResumeThread(threadHwnd);可以创建线程的消息队列。

10:说说Windows的内存管理,怎么实现内存共享?

FileMapping用于将存在于磁盘的文件放进一个进程的虚拟地址空间,并在该进程的虚拟地址空间中产生一个区域用于“存放”该文件,这个空间就叫做 File View,系统并同时产生一个File Mapping Object(存放于物理内存中)用于维持这种映射关系,这样当多个进程需要读写那个文件的数据时,它们的File View其实对应的都是同一个File  Mapping  Object,这样做可节省内存和保持数据的同步性,并达到数据共享的目的。

http://www.cnblogs.com/hlxs/p/4091623.html

时间: 2025-01-09 12:02:49

模态窗口其实就是在当前窗口调用系统的消息循环,响应用户的操作,将相关的消息发送到对应的窗口(转)的相关文章

.net 项目 调用webservice 出错,异常信息:对操作“xxx”的回复消息正文进行反序列化时出错。解决方案。

项目运行好好的,增加并更新WebService后,出错,捕获异常信息为:对操作“xxx”的回复消息正文进行反序列化时出错.解决方案. 认真分析异常信息后,得到关键提醒: {"读取 XML 数据时,超出最大名称表字符计数配额(16384).名称表是用于存储在处理 XML 时所遇到的字符串的数据结构 - 具有非重复元素名称.特性名称和特性值的长 XML 文档可能会触发此配额.通过更改在创建 XML 读取器时所使用的 XmlDictionaryReaderQuotas 对象的 MaxNameTable

iOS --调用系统通讯录

// 调用系统通讯录需要遵循两个代理ABPeoplePickerNavigationControllerDelegate,UINavigationControllerDelegate 相关类为ABPeoplePickerNavigationController // 系统通讯录自带导航栏,所有要model出来 // 初始化 ABPeoplePickerNavigationController *peoplePicker = [[ABPeoplePickerNavigationController

Android调用系统邮件类应用的正确实现方法

Android应用开发中,很多情况下免不了要调用手机上的邮件类应用,实现邮件发送的功能,这一般是通过调用系统已有的Intent来实现的.看到网上很多邮件发送都是调用action为android.content.Intent.ACTION_SEND的Intent来实现的,下面我们就来看下这种方式实现的效果如何. [使用Intent.ACTION_SEND方式] 具体的UI搭建我就不说了,很easy,直接看下发送的核心代码就行: String[] email = {"3802**[email pro

WPF中窗口控件的跨线程调用

原文:WPF中窗口控件的跨线程调用 在WinForm中,我们要跨线程访问窗口控件,只需要设置属性CheckForIllegalCrossThreadCalls = false;即可. 在WPF中要麻烦一下,同样的不允许跨线程访问,因为没有权限,访问了会抛异常: 没有CheckForIllegalCrossThreadCalls 属性,怎么办? 在WPF中的窗口控件都有一个Dispatcher属性,允许访问控件的线程:既然不允许直接访问,就告诉控件我们要干什么就好了. 方法如下: private

消息循环,注册窗口,创建窗口【图解】

本文是Win32编程基础 尽管Windows应用程序千变万化,令人眼花缭乱,但,消息机制和窗口过程却始终它们的基础,掌握了这两项技术,也就相当于把握住了问题的关键 DirectX编程也是建立在这个基础之上的,所以,在你可以熟练的进行简单的Win32编程之后DirectX编程也就触手可得. 1.1 简单的WIN32程序 在以前的C语言编程中,一个最简单的程序可以只有两行. void main(void) { printf "Hello World!"; } 而要实现同样功能的Window

窗口创建及消息循环

窗口创建 1. 自定义窗口类别           WNDCLASS 2. 注册窗口类               RegisterClass 3. 创建窗口                 CreateWindow/CreateWindowEx                 WM_CREATE 4. 显示窗口                 ShowWindow                                  WM_SIZE & WM_SHOWWINDOW 5. 更新窗口 

windows 消息循环和窗口与线程关系

/WinMain函数 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){ g_hinstance = hInstance; if( !Register("Main",WndProc) ) //注册窗口类 RegisterClassEx { MessageBox(NULL,"注册失败","Infor",M

Windows窗口消息循环及多线程之间关系

Windows中一个进程可以包含多个线程,由多个线程组成.在Windows应用程序中,窗体是由一种称为"UI线程(User Interface Thread)"的特殊类型的线程创建的.一个UI线程包含一个消息循环对列.在窗口运行过程中,按下控件或对窗口进行一些操作等同于向消息循环队列插入消息:然后由系统调用相应消息的响应函数,使用户操作得到响应. 根据该工作过程可知,当窗口某个消息的响应函数占用大量时间时,必定会影响窗口对下一个消息的响应.因此,对与那些比较耗时的操作的响应,使用多线程

调用系统的打电话,发短信,邮件,蓝牙

在开发某些应用时可能希望能够调用iOS系统内置的电话.短信.邮件.浏览器应用,此时你可以直接使用UIApplication的OpenURL:方法指定特定的协议来打开不同的系统应用.常用的协议如下: 打电话:tel:或者tel://.telprompt:或telprompt://(拨打电话前有提示) 发短信:sms:或者sms:// 发送邮件:mailto:或者mailto:// 启动浏览器:http:或者http:// 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16