Win32知识点整理(1)

本文详细介绍了Win32程序的创建步骤,包括注册窗口类、创建窗口和消息循环。探讨了Win32的字符集,包括SBCS、MBCS和Unicode。此外,解释了窗口类的注册和窗口程序的运行机制,与控制台程序的区别。同时,讨论了PeekMessage与GetMessage、TranslateMessage和DispatchMessage函数的差异,以及PostMessage与SendMessage的区别。最后,阐述了Win32消息机制、定时器的使用和用户自定义消息的实现方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、创建WIn32窗口程序的几个步骤及使用到的函数?

每一个Win32程序都有一个入口函数WinMain。在大多数的Win32程序中,WinMain函数要为应用程序完成以下几个步骤:

1.注册窗口类

2.创建主窗口

3.创建消息循环

1)每个窗口必须有一个窗口类。窗口类定义了一个窗口的属性,例如样式,图标,光标,菜单名称和窗口过程名称。第一步是用类信息填充一个WNDCLASS结构。然后把WNDCLASS结构传递给RegisterClass函数。

2)通过调用CreatWindow函数来创建窗口。只有在这之后调用ShowWindow这个函数,系统才会显示之前创建的窗口。

3)一旦主窗口被创建和显示,WinMain函数可以执行它的主任务,即从示例程序消息队列中读取消息,然后把消息分配给适合的窗口处理。

系统不会直接把输入传递给应用程序。它会把用户通过鼠标和键盘的输入的消息同系统消息,其它应用程序消息一起,放到消息队列中。示例程序必须从消息队列中获取这些输入消息,然后分配给可以处理这些消息的窗口处理过程。

示例程序使用的消息循环如下:

while( GetMessage( &msg, NULL, 0, 0 ) )  {

                TranslateMessage( &msg );

               DispatchMessage( &msg );    }

GetMessage函数可以从消息队列中获取消息。DispatchMessage函数可以把消息分配给合适的窗口处理过程。TranslateMessage函数可以把虚拟键码(virtual-key)翻译成字符消息。


2、Win32有哪些字符集?

第一种编码方案是单字节字符集,或者叫SBCS。所有的字符都是一个字节长。ASCII是SBCS的一个特例。一个字符0标志着一个SBCS字符串的结束。

第二种编码方案是多字节字符集,或者叫MBCS。 多字节编码方案包含了单字节的字符和多于一个字节的字符。在Windows系统中使用的多字节字符集有两种字符类型,单字节字符和双字节字符。因为Windows中使用的多字节字符集最大的字符是双字节的,所以我们通常用双字节字符集,或者叫DBCS来代替MBCS。

第三种编码方案是Unicode。Unicode是一种所有字符都是两个字节长的编码方案。Unicode字符有时被叫做宽字符,因为它们比单字节字符更宽(占用更多存储空间)。要注意到Unicode不能被考虑成一种多字节字符编码方案。一个明显的特征是Unicode字符的长度和MBCS的长度不一样。Unicode字符串都是以两个字符0来结束的。


3、窗口类的分类?

WinMain()是程序的入口,它相当于一个中介人的角色,把应用程序(指小窗口)介绍给windows。

首要的一步是登记应用程序的窗口类。

窗口种类是定义窗口属性的模板,这些属性包括窗口式样,鼠标形状,菜单等等。窗口种类也指定处理该类中所有窗口消息的窗口函数。只有先建立窗口种类,才能根据窗口种类来创建Windows应用程序的一个或多个窗口。创建窗口时,还可以指定窗口独有的附加特性。窗口类不能重名。在建立窗口类后,必须向Windows登记。  

建立窗口类就是用WNDCLASS结构定义一个结构变量,在这个程序中就是指 WNDCLASS wc 然后用自己设计的窗口属性的信息填充结构变量wc的域。要WinMain登记窗口类,首先要填写一个WNDCLASS结构。


4、win32窗口程序运行机制与控制台程序运行机制的区别?

都是工作在32位Windows环境的程序。 其中Win32 Application 就是普通的常见的窗口应用程序,当然有的界面做得比较个性化,比如圆形的、不规则形状的…… 它们都是所谓的GUI(图形用户接口),我们可以通过鼠标点击来完成控制。 
而Win32 Console Application(win32控制台应用程序)往往是像MS-DOS窗口(XP中叫命令提示符)的样子出现,我们得用键盘输入各种命令来使用它; 或者叫CUI(字符用户接口)。


5、PeekMessage与GetMessage的对比?

相同点:都用于查看应用程序消息队列,有消息时将队列中的消息派发出去。

不同点:
无论应用程序消息队列是否有消息,PeekMessage函数都立即返回,程序得以继续执行后面的语句(无消息则执行其它指令,有消息时一般要将消息派发出去,再执行其它指令)。

GetMessage函数只有在消息对立中有消息时返回,队列中无消息就会一直等,直至下一个消息出现时才返回。在等的这段时间,应用程序不能执行任何指令。


6、发送WM_QUIT消息使程序终止的内部过程?

在发送 WM_QUIT消息时,要使用PostMessage发送,否则窗口已经关闭,但任务管理器中进程还存在。

消息分为两种:队列化消息、非队列化消息

1)队列消息指消息队列里的消息,如WM_QUIT,用PostMessage发送的消息是队列消息。非队列消息指直接发送给窗口消息处理程序的消息,未经过消息队列,用SendMessage是非对列化消息。

因为GetMessage只有在从消息队列中取得WM_QUIT时,才能返回0,从而退出消息循环,结束程序,所以WM_QUIT必须是队列化消息。

2)总结:

WM_CLOSE 消息发出的时候,用户可以根据自己的意愿来选择到底是否关闭,WM_DESTORY 是真的关闭一个窗口。WM_QUIT是退出一个应用程序。

注意:只有关闭了消息循环,应用程序的进程才真正退出(在任务管理器里消失)。

3)win32应用程序的完整退出过程:

点击窗口右上角的关闭按钮,发送WM_CLOSE消息。此消息处理中调用DestroyWindow函数,发送WM_DESTROY消息。此消息处理中调用PostQuitMessage(0)函数,发送WM_QUIT消息到消息队列中。GetMessage捕获到WM_QUIT,返回0,退出循环(应用程序真正退出)。

4)MFC应用程序的完整退出过程:

点击窗口右上角的关闭按钮,或选择【File/Close】,发出 WM_CLOSE消息。CMyFrameWnd 并没有设置WM_CLOSE 处理常式,于是交给预设之处理常式。预设函数对于WM_CLOSE 的处理方式是呼叫 ::DestroyWindow, 并因而发出WM_DESTROY。预设之WM_DESTROY 处理方式是呼叫::PostQuitMessage,因此发出WM_QUIT。CWinApp::Run 收到WM_QUIT 后会结束其内部之讯息回路, 然后呼叫ExitInstance,这是CWinApp 的?个虚拟函数。如果自己应用程序累CMyWinApp 改写了ExitInstance , 那么CWinApp::Run 所呼叫的就是CMyWinApp::ExitInstance,否则就是 CWinApp::ExitInstance。最后回到 AfxWinMain,执行 AfxWinTerm,结束程序。


7、TranslateMessage和DispatchMessage的区别?

1)TranslateMessage将虚拟键消息转换为字符消息。字符消息被送到调用线程的消息队列中,在下一次线程调用函数GetMessage或PeekMessage时被读出。

如果消息被转换(即,字符消息被送到线程的消息队列中),返回非零值。如果消息是 WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, 或 WM_SYSKEYUP,返回非零值,不考虑转换。如果消息没有转换(即,字符消息没被送到线程的消息队列中),返回值是零。

TranslateMessage函数只能用于转换由GetMessage或PeekMessage函数接收到的消息。 

2)DispatchMessage调度一个消息给窗口程序。通常调度从GetMessage取得的消息。消息被调度到的窗口程序即是MainProc()函数。

MSG结构必须包含有效的消息值。如果参数lpmsg指向一个WM_TIMER消息,并且WM_TIMER消息的参数IParam不为NULL,则调用IPa1ram指向的函数,而不是调用窗口程序。

3)总结:TranslateMessage函数将键盘消息转化,DispatchMessage函数将消息传给窗体函数去处理。


8、PostMessage和SendMessage的区别?

1)PostMessage只把消息放入队列,不管其他程序是否处理都返回,然后继续执行,这是个异步消息投放函数。而SendMessage必须等待其他程序处理消息完了之后才返回,继续执行,这是个同步消息投放函数。而且,PostMessage的返回值表示PostMessage函数执行是否正确;而SendMessage的返回值表示其他程序处理消息后的返回值。

2)如果在同一个线程内,PostMessage发送消息时,消息要先放入线程的消息队列,然后通过消息循环Dispatch到目标窗口。SendMessage发送消息时,系统直接调用目标窗口的消息处理程序,并将结果返回。SendMessage在同一线程中发送消息并不入线程消息队列。 如果在不同线程内。最好用PostThreadMessage代替。


9、win32消息机制获取消息的过程?

有外部消息被触发时(按键,移动或按下鼠标,按下窗口上的某个button),Windows系统会依照消息的类型将它们分别放入System message quqeue和Application message quqeue中;然后消息循环中GetMessage(...)从上述两种队列中取出消息。

1)如果取出的是系统消息队列中的消息(virtual-key messages),则要通过TranslateMessage(...)将它们转换成character messages,并通过调用DispachMessage()将该virtual-key message重新传给Windows系统,用于通知系统已经对一个virtual-key message消息进行了转换,这样系统就会发将转换的结果放入Application message quqeue中,以便下次线程通过GetMessage(..)或PeekMessage(...)调用获得。

2)如果取出的是Application message quqeue中消息,则TranslateMessage(...)对其没有任何作用,并且DispachMessage()的功能不是用于通告系统有消息被转换,而是将要被处理的消息发给系统,让系统去调用相应的窗口过程处理函数。


10、Win32 API中使用定时器的方法?

1)SetTimer(HWND,UINT,UINT,TIMERPROC);

第一个参数设置为捕获该定时消息的窗口句柄, 第二个参数是定时器的id,第三个是以毫秒为单位的定时长度,最后一个参数设置为NULL,可以使窗口的回调函数进行处理WM_TIMER消息。一般来说,在窗口创建时进行SetTimer调用;在回调函数中添加WM_TIMER的响应。然后再窗口销毁的时候进行计时器的销毁:KillTimer(HWND,UINT);参数分别是窗口句柄和定时器ID。

2)SetTimer(HWND,UINT,UINT,TIMERPROC);

与第一种方法唯一的区别就是最后一个参数不是NULL,而是一个自己定义的回调函数,这样,WM_TIMER消息将被自己定义回调函数获取,进行处理。同样要在结束使用的时候KillTimer(HWND,UINT);

3)IDtimer = SetTimer(HWND,UINT,UINT,TIMERPROC);

将第一个参数设置为NULL ,第二个参数设置为0,第三个和第四个参数的设置与第二种方法一致,这样创建一个定时器将返回一个定时器ID,在销毁定时器时调用KillTimer(NULL,IDtimer)。这种方式适合多次定时容易混淆定时器ID的程序,因为其返回值管理定时器ID,而不要自己去管理。


11、用户自定义消息如何实现?

第一步:定义消息。推荐用户自定义消息至少是WM_USER+100,因为很多新控件也要使用WM_USER消息。

#define WM_MY_MESSAGE (WM_USER+100)  

第二步:实现消息处理函数。该函数使用WPRAM和LPARAM参数并返回LPESULT。  

LPESULT CMainFrame::OnMyMessage(WPARAM wParam, LPARAM lParam)  

{  // TODO: 处理用户自定义消息  ...  return 0;  }  

第三步:在类头文件的AFX_MSG块中说明消息处理函数:

class CMainFrame:public CMDIFrameWnd  
{  ...  // 一般消息映射函数  

protected:  
// {{AFX_MSG(CMainFrame)  
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);  
afx_msg void OnTimer(UINT nIDEvent);  
afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);  
//}}AFX_MSG  
DECLARE_MESSAGE_MAP()  
}  

第四步:在用户类的消息块中,使用ON_MESSAGE宏指令将消息映射到消息处理函数中。

BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)  
//{{AFX_MSG_MAP(CMainFrame)  
ON_WM_CREATE()  
ON_WM_TIMER()  
ON_MESSAGE(WM_MY_MESSAGE, OnMyMessage)  
//}}AFX_MSG_MAP  
END_MESSAGE_MAP()  


12、模式对话框和非模式对话框的区别?

一、创建的区别

在WIN32中,模式对话框的创建一般是使用DialogBox来进行创建的。而非模式对话框则是利用CreateWindow来创建的。在MFC或是WTL中,模式对话框一般是使用DoModal,而非模式对话框的创建则是使用Create。

模式对话框创建后,程序的其他窗口便不能进行操作,必须将该窗口关闭后,其他窗口才能进行操作。而非模式对话框则无需这样,它不强制要求用户立即反应,而是与其他窗口同时接受用户操作。

二、消息响应的区别

模式对话框工作的时候,它有内部的消息泵机制,控件之间的交互不用我们人为的去控制,系统会帮助我们去处理。非模式对话框则像普通窗口一样,则由WinMain中书写的消息循环驱动。但由于是对话框,它对一些消息有特殊的处理。因此,在消息循环中,需要先对对话框提供截获消息的机会。

三、销毁的区别

模式对话框的销毁是使用EndDialog,而非模式对话框的销毁是使用DestroyWindow。

非模式对话框,用户关闭对话框时,对话框消息处理函数将收到WM_CLOSE消息,接到后调用DestroyWindow以销毁非模式对话框。

模式对话框,则一般响应IDOK和IDCANCEL。在PPC上,我们对于OK键和X键的处理要注意这点。



 





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值