转:windows消息传递机制

2023-10-27

     Windows是一个消息(Message)驱动系统。Windows的消息提供了应用程序之间、应用程序与Windows系统之间进行通信的手段。应用程序想要实现的功能由消息来触发,并且靠对消息的响应和处理来完成。必须注意的是,消息并非是抢占性的,无论事件的缓急,总是按照到达的先后派对,依次处理(一些系统消息除外),这样可能使一些实时外部事件得不到及时处理。

      Windows的应用程序一般包含窗口(Window),它主要为用户提供一种可视化的交互方式,窗口是总是在某个线程(Thread)内创建的。Windows系统通过消息机制来管理交互,消息(Message)被发送,保存,处理,一个线程会维护自己的一套消息队列(Message Queue),以保持线程间的独占性。队列的特点无非是先进先出,这种机制可以实现一种异步的需求响应过程。

目录:

1、消息

2  、消息类型

3 、消息队列(Message Queues)

4 、队列消息(Queued Messages)和非队列消息(Non-Queued Messages)

5 、PostMessage(PostThreadMessage), SendMessage

6 、GetMessage, PeekMessage

7 、TranslateMessage, TranslateAccelerator

8、(消息死锁( Message Deadlocks)

9、BroadcastSystemMessage

10、消息的处理

11、MFC的消息映射

12、消息反射机制

1、消息

    消息系统对于一个win32程序来说十分重要,它是一个程序运行的动力源泉。一个消息,是系统定义的一个32位的值,他唯一的定义了一个事件,向Windows发出一个通知,告诉应用程序某个事情发生了。例如,单击鼠标、改变窗口尺寸、按下键盘上的一个键

都会使Windows发送一个消息给应用程序。

    消息本身是作为一个记录传递给应用程序的,这个记录中包含了消息的类型以及其他信息。例如,对于单击鼠标所产生的消息来

说,这个记录中包含了单击鼠标时的坐标。这个记录类型叫做MSG,MSG含有来自windows应用程序消息队列的消息信息,它在

Windows中声明如下:
typedef struct tagMsg
{
HWND hwnd;          // 接受该消息的窗口句柄
UINT message;         // 消息常量标识符,也就是我们通常所说的消息号
WPARAM wParam;     // 32位消息的特定附加信息,确切含义依赖于消息值
LPARAM lParam;       // 32位消息的特定附加信息,确切含义依赖于消息值
DWORD time;         // 消息创建时的时间
POINT pt;             // 消息创建时的鼠标/光标在屏幕坐标系中的位置
}MSG;
    消息可以由系统或者应用程序产生。系统在发生输入事件时产生消息。举个例子, 当用户敲键, 移动鼠标或者单击控件。系统也产生消息以响应由应用程序带来的变化, 比如应用程序改变系统字体,改变窗体大小。应用程序可以产生消息使窗体执行任务,或者与其他应用程序中的窗口通讯。
2、消息类型
1) 系统定义消息(System-Defined Messages)
        在SDK中事先定义好的消息,非用户定义的,其范围在[0x0000, 0x03ff]之间, 可以分为以下三类:
1> 窗口消息(Windows Message)
       与窗口的内部运作有关,如创建窗口,绘制窗口,销毁窗口等。可以是一般的窗口,也可以是Dialog,控件等。
如:WM_CREATE, WM_PAINT, WM_MOUSEMOVE, WM_CTLCOLOR, WM_HSCROLL...
2> 命令消息(Command Message)
        与处理用户请求有关, 如单击菜单项或工具栏或控件时, 就会产生命令消息。
WM_COMMAND, LOWORD(wParam)表示菜单项,工具栏按钮或控件的ID。如果是控件, HIWORD(wParam)表示控件消息类型
3> 控件通知(Notify Message)
        控件通知消息, 这是最灵活的消息格式, 其Message, wParam, lParam分别为:WM_NOTIFY, 控件ID,指向NMHDR的指针。NMHDR包含控件通知的内容, 可以任意扩展。
2) 程序定义消息(Application-Defined Messages)
        用户自定义的消息, 对于其范围有如下规定:
WM_USER: 0x0400-0x7FFF      (ex. WM_USER+10)
WM_APP(winver> 4.0): 0x8000-0xBFFF (ex.WM_APP+4)
RegisterWindowMessage: 0xC000-0xFFFF
3、消息队列(Message Queues)
 Windows中有两种类型的消息队列
1) 系统消息队列(System Message Queue)
        这是一个系统唯一的Queue,设备驱动(mouse, keyboard)会把操作输入转化成消息存在系统队列中,然后系统会把此消息放到目标窗口所在的线程的消息队列(thread-specific message queue)中等待处理
2) 线程消息队列(Thread-specific Message Queue)
        每一个GUI线程都会维护这样一个线程消息队列。(这个队列只有在线程调用GDI函数时才会创建,默认不创建)。然后线程消息队列中的消息会被送到相应的窗口过程(WndProc)处理.
注意: 线程消息队列中WM_PAINT,WM_TIMER只有在Queue中没有其他消息的时候才会被处理,WM_PAINT消息还会被合并以提高效率。其他所有消息以先进先出(FIFO)的方式被处理。
4、队列消息(Queued Messages)和非队列消息(Non-Queued Messages)

1)队列消息(Queued Messages)
        消息会先保存在消息队列中,消息循环会从此队列中取消息并分发到各窗口处理  、如鼠标,键盘消息。
2) 非队列消息(NonQueued Messages)
        消息会绕过系统消息队列和线程消息队列直接发送到窗口过程被处理  如: WM_ACTIVATE, WM_SETFOCUS, WM_SETCURSOR, WM_WINDOWPOSCHANGED
注意: postMessage发送的消息是队列消息,它会把消息Post到消息队列中; SendMessage发送的消息是非队列消息, 被直接送到窗口过程处理.

队列消息和非队列消息的区别
        从消息的发送途径来看,消息可以分成2种:队列消息和非队列消息。消息队列由可以分成系统消息队列和线程消息队列。系统消息队列由Windows维护,线程消息队列则由每个GUI线程自己进行维护,为避免给non-GUI现成创建消息队列,所有线程产生时并没有消息队列,仅当线程第一次调用GDI函数时系统才给线程创建一个消息队列。队列消息送到系统消息队列,然后到线程消息队列;非队列消息直接送给目的窗口过程。
     对于队列消息,最常见的是鼠标和键盘触发的消息,例如WM_MOUSERMOVE,WM_CHAR等消息,还有一些其它的消息,例如:WM_PAINT、 WM_TIMER和WM_QUIT。当鼠标、键盘事件被触发后,相应的鼠标或键盘驱动程序就会把这些事件转换成相应的消息,然后输送到系统消息队列,由 Windows系统去进行处理。Windows系统则在适当的时机,从系统消息队列中取出一个消息,根据前面我们所说的MSG消息结构确定消息是要被送往那个窗口,然后把取出的消息送往创建窗口的线程的相应队列,下面的事情就该由线程消息队列操心了,Windows开始忙自己的事情去了。线程看到自己的消息队列中有消息,就从队列中取出来,通过操作系统发送到合适的窗口过程去处理。
     一般来讲,系统总是将消息Post在消息队列的末尾。这样保证窗口以先进先出的顺序接受消息。然而,WM_PAINT是一个例外,同一个窗口的多个 WM_PAINT被合并成一个 WM_PAINT 消息, 合并所有的无效区域到一个无效区域。合并WM_PAIN的目的是为了减少刷新窗口的次数。

      非队列消息将会绕过系统队列和消息队列,直接将消息发送到窗口过程,。系统发送非队列消息通知窗口,系统发送消息通知窗口。例如,当用户激活一个窗口系统发送WM_ACTIVATE, WM_SETFOCUS, and WM_SETCURSOR。这些消息通知窗口它被激活了。非队列消息也可以由当应用程序调用系统函数产生。例如,当程序调用SetWindowPos系统发送WM_WINDOWPOSCHANGED消息。一些函数也发送非队列消息,例如下面我们要谈到的函数。

5 、PostMessage(PostThreadMessage), SendMessage
        PostMessage:把消息放到指定窗口所在的线程消息队列中后立即返回。 PostThreadMessage:把消息放到指定线程的消息队列中后立即返回。
        SendMessage:直接把消息送到窗口过程处理, 处理完了才返回。

PostMessage(异步)和SendMessage(同步)的区别

a、 PostMessage 是异步的,SendMessage 是同步的。

         PostMessage 只把消息放到队列,不管消息是不是被处理就返回,消息可能不被处理;

        SendMessage等待消息被处理完了才返回,如果消息不被处理,发送消息的线程将一直处于阻塞状态,等待消息的返回。

b、 同一个线程内:

          SendMessage 发送消息时,由USER32.DLL模块调用目标窗口的消息处理程序,并将结果返回,SendMessage 在同一个线程里面发送消息不进入线程消息队列;PostMessage 发送的消息要先放到消息队列,然后通过消息循环分派到目标窗口(DispatchMessage)。

c、不同线程:

             SendMessage 发送消息到目标窗口的消息队列,然后发送消息的线程在USER32。DLL模块内监视和等待消息的处理结果,直到目标窗口的才处理返回,SendMessage在返回之前还需要做许多工作,如响应别的线程向它发送的SendMessage().PostMessge() 到别的线程的时候最好使用PostThreadMessage   代替。PostMessage()的HWND 参数可以为NULL,相当于PostThreadMessage() + GetCrrentThreadId.

d、系统处理消息。

       系统只处理(marshal)系统消息(0--WM_USER),发送用户消息(用户自己定义)时需要用户自己处理。

        使用PostMessage,SendNotifyMessage,SendMessageCallback等异步函数发送系统消息时,参数不可以使用指针,因为发送者不等待消息的处理就返回,接收者还没有处理,指针就有可能被释放了,或则内容变化了。

e、在Windows 2000/XP,每个消息队列最多只能存放一定数量的消息,超过的将不会被处理就丢掉。系统默认是10000;:[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows] USERPostMessageLimit

6 、GetMessage, PeekMessage
PeekMessage会立即返回    可以保留消息
GetMessage在有消息时返回  会删除消息

PeekMessage和GetMessage函数的主要区别有:
        a. GetMessage的主要功能是从消息队列中“取出”消息,消息被取出以后,就从消息队列中将其删除;而PeekMessage的主要功能是“窥视”消息,如果有消息,就返回true,否则返回false。也可以使用PeekMessage从消息队列中取出消息,这要用到它的一个参数(UINT wRemoveMsg),如果设置为PM_REMOVE,消息则被取出并从消息队列中删除;如果设置为PM_NOREMOVE,消息就不会从消息队列中取出。
        b. 如果GetMessage从消息队列中取不到消息,则线程就会被操作系统挂起,等到OS重新调度该线程时,两者的性质不同:使用GetMessage线程仍会被挂起,使用PeekMessage线程会得到CPU的控制权,运行一段时间。
        c、GetMessage每次都会等待消息,直到取到消息才返回;而PeekMessage只是查询消息队列,没有消息就立即返回,从返回值判断是否取到了消息。
我们也可以说,PeekMessage是一个具有线程异步行为的函数,不管消息队列中是否有消息,函数都会立即返回。而GetMessage则是一个具有线程同步行为的函数,如果消息队列中没有消息的话,函数就会一直等待,直到消息队列中至少有一条消息时才返回。
如果消息队列中没有消息,PeekMessage总是能返回,这就相当于在执行一个循环,如果消息队列一直为空, 它就进入了一个死循环。GetMessage则不可能因为消息队列为空而进入死循环。

联系:

        在Windows的内部,GetMessage和PeekMessage执行着相同的代码,Peekmessage和Getmessage都是向系统的消息队列中取得消息,并将其放置在指定的结构。

区别:

PeekMessage:有消息时返回TRUE,没有消息返回FALSE

GetMessage:有消息时且消息不为WM_QUIT时返回TRUE,如果有消息且为WM_QUIT则返回FALSE,没有消息时不返回。

GetMessage:取得消息后,删除除WM_PAINT消息以外的消息。

PeekMessage:取得消息后,根据wRemoveMsg参数判断是否删除消息。PM_REMOVE则删除,PM_NOREMOVE不删除。

The PeekMessage function normally does not remove WM_PAINT messages from the queue. WM_PAINT messages remain in the queue until they are processed. However, if a WM_PAINT message has a null update region, PeekMessage does remove it from the queue.

不能用PeekMessage从消息队列中删除WM_PAINT消息,从队列中删除WM_PAINT消息可以令窗口显示区域的失效区域变得有效(刷新窗口),如果队列中包含WM_PAINT消息程序就会一直while循环了。

7 、TranslateMessage, TranslateAccelerator
         TranslateMessage: 把一个virtual-key消息转化成字符消息(character message),并放到当前线程的消息队列中,消息循环下一次取出处理。
        TranslateAccelerator: 将快捷键对应到相应的菜单命令。它会把WM_KEYDOWN 或 WM_SYSKEYDOWN转化成快捷键表中相应的WM_COMMAND 或WM_SYSCOMMAND消息, 然后把转化后的 WM_COMMAND或WM_SYSCOMMAND直接发送到窗口过程处理, 处理完后才会返回。

8、(消息死锁( Message Deadlocks)
假设有线程A和B, 现在有以下下步骤
        1) 线程A SendMessage给线程B, A等待消息在线程B中处理后返回
        2) 线程B收到了线程A发来的消息,并进行处理, 在处理过程中,B也向线程A SendMessgae,然后等待从A返回。  因为此时, 线程A正等待从线程B返回, 无法处理B发来的消息, 从而导致了线程A,B相互等待, 形成死锁。多个线程也可以形成环形死锁。
可以使用 SendNotifyMessage或SendMessageTimeout来避免出现死锁。

9、BroadcastSystemMessage
        我们一般所接触到的消息都是发送给窗口的, 其实, 消息的接收者可以是多种多样的,它可以是应用程序(applications), 可安装驱动(installable drivers), 网络设备(network drivers), 系统级设备驱动(system-level device drivers)等,
BroadcastSystemMessage这个API可以对以上系统组件发送消息。

10、消息的处理
        接下来我们谈一下消息的处理,首先我们来看一下VC中的消息泵:

while(GetMessage(&msg, NULL, 0, 0))
{
       if(!TranslateAccelerator(msg.hWnd, hAccelTable, &msg))
{
            TranslateMessage(&msg);
            DispatchMessage(&msg);
       }
}

TranslateMessage(转换消息):

        用来把虚拟键消息转换为字符消息。由于Windows对所有键盘编码都是采用虚拟键的定义,这样当按键按下时,并不得字符消息,需要键盘映射转换为字符的消息。

TranslateMessage函数

        用于将虚拟键消息转换为字符消息。字符消息被投递到调用线程的消息队列中,当下一次调用GetMessage函数时被取出。当我们敲击键盘上的某个字符键时,系统将产生WM_KEYDOWN和WM_KEYUP消息。这两个消息的附加参数(wParam和lParam)包含的是虚拟键代码和扫描码等信息,而我们在程序中往往需要得到某个字符的ASCII码,TranslateMessage这个函数就可以将WM_KEYDOWN和WM_ KEYUP消息的组合转换为一条WM_CHAR消息(该消息的wParam附加参数包含了字符的ASCII码),并将转换后的新消息投递到调用线程的消息队列中。注意,TranslateMessage函数并不会修改原有的消息,它只是产生新的消息并投递到消息队列中。

也就是说TranslateMessage会发现消息里是否有字符键的消息,如果有字符键的消息,就会产生WM_CHAR消息,如果没有就会产生什么消息。

DispatchMessage(分派消息):

把 TranslateMessage转换的消息发送到窗口的消息处理函数,此函数在窗口注册时已经指定。
        首先,GetMessage从进程的主线程的消息队列中获取一个消息并将它复制到MSG结构,如果队列中没有消息,则GetMessage函数将等待一个消息的到来以后才返回。如果你将一个窗口句柄作为第二个参数传入GetMessage,那么只有指定窗口的的消息可以从队列中获得。GetMessage也可以从消息队列中过滤消息只接受消息队列中落在范围内的消息。这时候就要利用GetMessage/PeekMessage指定一个消息过滤器。这个过滤器是一个消息标识符的范围或者是一个窗体句柄,或者两者同时指定。当应用程序要查找一个后入消息队列的消息是很有用。WM_KEYFIRST 和 WM_KEYLAST 常量用于接受所有的键盘消息。 WM_MOUSEFIRST 和 WM_MOUSELAST 常量用于接受所有的鼠标消息。
然后TranslateAccelerator判断该消息是不是一个按键消息并且是一个加速键消息,如果是,则该函数将把几个按键消息转换成一个加速键消息传递给窗口的回调函数。处理了加速键之后,函数TranslateMessage将把两个按键消息WM_KEYDOWN和WM_KEYUP转换成一个 WM_CHAR,不过需要注意的是,消息WM_KEYDOWN,WM_KEYUP仍然将传递给窗口的回调函数。    
处理完之后,DispatchMessage函数将把此消息发送给该消息指定的窗口中已设定的回调函数。如果消息是WM_QUIT,则 GetMessage返回0,从而退出循环体。应用程序可以使用PostQuitMessage来结束自己的消息循环。通常在主窗口的 WM_DESTROY消息中调用。
11、MFC的消息映射
         使用MFC编程时,消息发送和处理的本质和Win32相同,但是,它对消息处理进行了封装,简化了程序员编程时消息处理的复杂性,它通过消息映射机制来处理消息,程序员不必去设计和实现自己的窗口过程。
说白了,MFC中的消息映射机制实质是一张巨大的消息及其处理函数对应表。消息映射基本上分为两大部分:
在头文件(.h)中有一个宏DECLARE_MESSAGE_MAP(),它放在类的末尾,是一个public属性的;与之对应的是在实现部分(.cpp)增加了一个消息映射表,内容如下:
BEGIN_MASSAGE_MAP(当前类,当前类的基类)
//{{AFX_MSG_MAP(CMainFrame)
消息的入口项
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
但是仅是这两项还不足以完成一条消息,要是一个消息工作,必须还有以下3个部分去协作:
1、在类的定义中加入相应的函数声明;
2、在类的消息映射表中加入相应的消息映射入口项;
3、在类的实现中加入相应的函数体;
消息的添加
(1)、利用Class Wizard实现自动添加
        在菜单中选择View -> Class Wizard激活Class Wizard,选择Message Map标签,从Class name组合框中选取我们想要添加消息的类。在Object IDs列表框中,选取类的名称。此时,Messages列表框显示该类的可重载成员函数和窗口消息。可重载成员函数显示在列表的上部,以实际虚构成员函数的大小写字母来表示。其他为窗口消息,以大写字母出现。选中我们要添加的消息,单击Add Funtion按钮,Class Wizard自动将该消息添加进来。
有时候,我们想要添加的消息在Message列表中找不到,我们可以利用Class Wizard上Class Info标签以扩展消息列表。在该页中,找到Message Filter组合框,通过它可以改变首页中Messages列表框中的选项。
(2)、手动添加消息
 如果Messages列表框中确实没有我们想要的消息,就需要我们手工添加:
        1)在类的.h文件中添加处理函数的声明,紧接着在//}}AFX_MSG行之后加入声明,注意,一定要以afx_msg开头。
通常,添加处理函数声明的最好的地方是源代码中Class Wizard维护的表的下面,在它标记其领域的{{ }}括弧外面。这些括弧中的任何东西都有可能会被Class Wizard销毁。
        2)接着,在用户类的.cpp文件中找到//}}AFX_MSG_MAP行,紧接在它之后加入消息入口项。同样,也放在{{ }}外面。
        3)最后,在该文件中添加消息处理函数的实体。
对于能够使用Class Wizard添加的消息,尽量使用Class Wizard添加,以减少我们的工作量;对于不能使用Class Wizard添加的消息和自定义消息,需要手动添加。总体说来,MFC的消息编程对用户来说,相对比较简单,在此不再使用实例演示。
        12、消息反射机制
什么叫消息反射?
         父窗口将控件发给它的通知消息,反射回控件进行处理(即让控件处理这个消息),这种通知消息让控件自己处理的机制叫做消息反射机制。
        通过前面的学习我们知道,一般情况下,控件向父窗口发送通知消息,由父窗口处理这些通知消息。这样,父窗口(通常是一个对话框)会对这些消息进行处理,换句话说,控件的这些消息处理必须在父窗口类体内,每当我们添加子控件的时候,就要在父窗口类中复制这些代码。很明显,这对代码的维护和移植带来了不便,而且,明显背离C++的对象编程原则。
        从4.0版开始,MFC提供了一种消息反射机制(Message Reflection),可以把控件通知消息反射回控件。具体地讲,对于反射消息,如果控件有该消息的处理函数,那么就由控件自己处理该消息,如果控件不处理该消息,则框架会把该消息继续送给父窗口,这样父窗口继续处理该消息。可见,新的消息反射机制并不破坏原来的通知消息处理机制。
消息反射机制为控件提供了处理通知消息的机会,这是很有用的。如果按传统的方法,由父窗口来处理这个消息,则加重了控件对象对父窗口的依赖程度,这显然违背了面向对象的原则。若由控件自己处理消息,则使得控件对象具有更大的独立性,大大方便了代码的维护和移植。
        实例M8:简单地演示MFC的消息反射机制。(见附带源码 工程M8)
     开VC++ 6.0,新建一个基于对话框的工程M8。
在该工程中,新建一个CMyEdit类,基类是CEdit。接着,在该类中添加三个变量,如下:
private:
CBrush m_brBkgnd;
COLORREF m_clrBkgnd;
COLORREF m_clrText;
在CMyEdit::CMyEdit()中,给这三个变量赋初值:
{
m_clrBkgnd = RGB( 255, 255, 0 );
m_clrText = RGB( 0, 0, 0 );
m_brBkgnd.CreateSolidBrush(RGB( 150, 150, 150) );
}
打开ClassWizard,类名为CMyEdit,Messages处选中“=WM_CTLCOLOR”,您是否发现,WM_CTLCOLOR消息前面有一个等号,它表示该消息是反射消息,也就是说,前面有等号的消息是可以反射的消息。
消息反射函数代码如下:
HBRUSH CMyEdit::CtlColor(CDC* pDC, UINT nCtlColor)
{
    // TODO: Change any attributes of the DC here
    pDC->SetTextColor( m_clrText );//设置文本颜色
    pDC->SetBkColor( m_clrBkgnd );//设置背景颜色
     //请注意,在我们改写该函数的内容前,函数返回NULL,即return NULL;
    //函数返回NULL将会执行父窗口的CtlColor函数,而不执行控件的CtlColor函数
    //所以,我们让函数返回背景刷,而不返回NULL,目的就是为了实现消息反射
    return m_brBkgnd; //返回背景刷
}
在IDD_M8_DIALOG对话框中添加一个Edit控件,使用ClassWizard给该Edit控件添加一个CMyEdit类型的变量m_edit1,把Edit控件和CMyEdit关联起来。
————————————————

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

转:windows消息传递机制 的相关文章

  • 如何从头开始启动 MFC 应用程序?

    换句话说 来自一个空白的 win32 项目 无向导 这就是我所在的地方 预处理器定义 WIN32 链接器 gt 系统 gt 子系统 控制台 int tmain int nRetCode 0 initialize MFC and print
  • 有效的 MFC ID 范围

    这让我很困惑 我正在读这个技术说明 https learn microsoft com en gb cpp mfc tn020 id naming and numbering conventions它指出 Prefix Resource t
  • DirectUI 的真相是什么? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我正在开发一个 Windows 桌面应用程序 它需要一个很棒的 UI 我现在使用Visual Studio和MFC 后来听说DirectU
  • 在MFC项目中使用多个资源文件

    我在 VS2015 中使用 MFC C 11 并且有一组独立的 GUI 我想在多个项目中使用它们 我知道这可以通过创建一个 rc 文件来实现 该文件可以包含在每个项目的主 rc 文件中 使用多个资源文件 https msdn microso
  • Boost::序列化和 MFC Doc/View 架构

    我正在移植现有的 MFC C 应用程序以对 XML 文件使用 Boost Serialization 我的 CDocument 对象包含应用程序的所有数据 我已将序列化函数实现为 template
  • SetWindowPos() 函数不移动窗口?

    我有一个对话框 我想将其放置在另一个对话框中 并相对于主对话框上的其中一个控件进行定位 void CspAceDlg DrawResultsArea CWnd pTabCtl GetDlgItem IDC BUILDTABS CRect r
  • 如何显示非模式对话框并立即在其中显示信息?

    我想在屏幕上显示一个无模式对话框并在其中显示一些信息 但是 如果我按照以下方式使用它 则会出现一些问题 function showdialog XXX heavy work update the dialog heavy work upda
  • 如何向现有 Win32 C++ 项目添加 MFC 支持?

    我正在创建一个 C 应用程序 它使用 Qt 创建 GUI 但是 我需要使用依赖于 MFC 的第三方库 用于 CString 等 无论如何 是否可以将 MFC 添加到我的应用程序中以允许我使用这个库 或者我需要自己重写它 I saw 这个问题
  • MFC:如何减少OnInitialUpdate()滚动的时间成本?

    我需要打印多行数据 每行都可以进行文本换行 因此高度会有所不同 要进行滚动 我需要导出总高度 由于每条线可能有不同的高度 我只能遍历每条线来累加高度 如下所示 void CMyScrollView OnInitialUpdate for a
  • MFC 控件上的文本 - Unicode 字符(例如日语)被截断

    背景 我正在开发一个 C MFC 应用程序 我们已经将其转换为显示 unicode 字符以支持外语 在大多数情况下 这是成功的并且 unicode 字符显示正确 但我遇到了一个问题 某些控件上的某些文本被截断 Example 在这里 您可以
  • MFC:如何捕获Web浏览器控件中的链接单击事件?

    我有一个带有 Web 控件的 MFC 应用程序 单击可单击链接时 它将使用 IE 打开 而不是默认浏览器 问题 有没有办法强制使用默认浏览器打开它 如果没有 我如何捕获链接单击事件 以便稍后可以操纵单击事件 谢谢 不 据我所知还没有 查看有
  • 如何发光最小。最大和关闭按钮?

    我按照以下指南使用 DWM API 创建自定义 Aero 框架 My work void CMainFrame OnActivate UINT nState CWnd pWndOther BOOL bMinimized CFrameWnd
  • MFC:如何在一个函数中捕获对话框每个控件的设置焦点

    我有 n 个对话框 它们具有相同的基本对话框 每个对话框都有自己的控件 编辑框 组合框 列表控件 etc 在基本对话框中 如何设置每个控件的焦点消息 例如 给出一个消息框 text Hello I got focus my ID is d
  • 在Linux上运行MFC程序

    我有一个相当大的基于 MFC 的程序 我的任务是让它在 Linux 上运行 我已经解释过 这需要将程序重新编写为带有 STL 的直接 C 更多工作 或者重新编写为 Qt C 更少工作 现在我被告知 我需要编写包装器以使每个 MFC 类在 L
  • 想要将 ColeDateTime 转换为 CTime

    我正在从数据库中读取日期时间ColeDateTime格式 我想将其转换为CTime获取日期 月份 年份和时间 CString repDt this will hold the datetime which i read from Datab
  • MFC CMenu 工具提示未显示

    我尝试使用类似的东西来设置 CMenu 项的工具提示 如所述here https stackoverflow com questions 2400180 mfc how to add tooltip in cmenu items 但它只是显
  • 实现批量记录获取

    在程序开始时 我需要将数据从 MS Access 数据库 mdb 读取到下拉控件中 这样做是为了每当用户在该控件中键入内容时 应用程序都可以自动完成 不管怎样 从数据库中读取数据花了很长时间 所以我想我应该实现批量行获取 这是我的代码 CS
  • .NET(或 MFC)的高速图形控件?

    我需要编写一个数字示波器类型的应用程序 有很多很棒的静态绘图控件 但我需要一些可以绘制每秒处理 4000 个样本的 16 条轨迹的东西 有人知道 NET 的高速图形控件吗 我什至会选择 MFC 因为它可以封装到 NET 控件中 谢谢您的帮助
  • Windows API 中逻辑坐标和设备坐标之间的混淆

    我一直在研究一个使用两个函数的 Visual Studio C Windows 应用程序项目SetWindowExt and SetViewportExt 我对这两个函数的作用以及为什么它们是必要的感到困惑 搜索这些函数 我得出了逻辑坐标和
  • MFC:如何设置CEdit框的焦点?

    我正在开发我的第一个简单的 MFC 项目 但我正在努力解决一个问题 想要设置所有的焦点CEdit其中一个对话框中的框 我的想法是 当打开对话框时 焦点位于第一个编辑框上 然后使用 选项卡 在它们之间交换 我看到了方法SetFocus 但我无

随机推荐

  • Mybatis底层源码分析(最详细的版本)

    Mybatis底层源码分析 最详细的版本 1 概要介绍 MyBatis 是一款优秀的持久层框架 也是当前最流行的java持久层框架之一 它内部封装了jdbc 使开发 者只需要关注sql语句本身 而不需要花费精力去处理加载驱动 创建连接 创建
  • 网络编程知识预备(2) ——TCP三次握手与四次挥手、流量控制(滑动窗口)、拥塞控制、半连接状态、2MSL

    参考 浅显易懂的三次握手与四次挥手 作者 丶PURSUING 发布时间 2021 03 19 09 33 20 网址 https blog csdn net weixin 44742824 article details 114990198
  • python3 面向对象_Python3快速入门(六)——Python3面向对象

    Python3快速入门 六 Python3面向对象 一 面向对象技术简介 1 面向对象简介 面向对象编程 Object Oriented Programing OOP 是一种编程思想 OOP把对象当成程序的一个基本单元 一个对象包含数据和操
  • antd date-picker 默认时间设置问题

    一 官网给出的例子
  • Python编程:通讯录(文件读取)

    描述 读取附件中的csv文件 通讯录信息 放入字典中 后两项以列表形式做为字典的值 并依次输出其中的信息 文件内数据不需要修改 输出时数据之间以空格间隔 编码格式使用GBK 输入 A 时 按行输出文件信息 输入 D 时 直接输出字典内容 输
  • vue3 props属性基本使用梳理

    前言 vue2中props属性的使用是比较统一的基本就一种方式 但是vue3中其实方式是比较多的 因此就打算梳理一下 会按照选项式和组合式进行梳理 包括属性的定义 取值以及属性的监听 应该是叫单文件组件和组合式API 不知道vue官方是根据
  • 递归->栈->队列面试题

    本文所有程序均已测试通过 测试结果图就不一个一个再截图了 读者可以自己copy验证一下 后期我会把思路图补出来 1 行走机器人问题 货架N个 机器人初始位置在pos 经过minutes分钟后到达T有多少种方案 行走机器人问题 货架N个 机器
  • 使用Hexo从0到1搭建个人博客详细教程(超详细,超简单)

    看完这篇 轻轻松松搭建个人博客 校花 班花 额 额 看了就会的博客搭建教程 一 搭建前的软件准备 git node 二 安装hexo 完成简单本地页面展示 三 将Hexo部署到Github 1 Github创建个人仓库 2 生成ssh添加到
  • WebStorm功能特点以及使用指南

    WebStorm功能特点以及使用指南 首先看看WebStorm合其他的IDE有什么特别之处 1 自动保存 不需要你一次又一次地ctrl s啦 所有的操作都直接存储 当然 万一键盘误操作也会被立即存储 不过我们可以通过本地版本控制解决这个问题
  • 创建型模式-建造者模式理解

    1 前言 首先建造者模式适合下面的场景 进行使用 假设不同的对象有着基本的共同特点 或者配合前端进行页面布局 进行构建一个复杂的对象 那么可以参考工厂方法模式进行抽取对象 并进行解耦 达到一个设计符合要求的对象的过程 eg 1 保险产品 前
  • python自适应图片大小_python – 如何在Pygame中将图像缩放到屏幕尺寸

    您可以使用pygame transform scale缩放图像 import pygame picture pygame image load filename picture pygame transform scale picture
  • 小世界网络和复杂网络+python代码实现

    文章目录 小世界网络 复杂网络的特性 平均路径长度L 聚集系数C 度及度分布 小世界效应 规则网络 随机网络 小世界网络 无标度网络 python 代码 生成小世界网络 规则网络 喜欢的话请关注我们的微信公众号 你好世界炼丹师 公众号主要讲
  • 头文件重复定义问题解决“C1014错误“

    比如现在有三个文件 两个头文件 一个 cpp文件 header1 h include header2 h int fun2 header2 h include header1 h int fun main cpp include heade
  • Git学习笔记----基础运用

    安装Git Windows 进入官网下载或百度网盘下载 Git V2 23 x64 提取码 uf2x Ubuntu sudo apt get install git 安装完成之后打开git命令行 Ubuntu命令行即可操作 输入以下代码 查
  • Linux内核设计与实现 第六章 内核数据结构

    目录 1 单向链表和双向链表 编辑 编辑 2 环形链表 3 沿链表移动 4 Linux内核中的实现 5 操作链表 6 遍历链表 6 2队列 1 kfifo 2 创建队列 3 推入队列数据 4 摘取队列数据 5 获取队列数据 6 重置和撤销队
  • hook控制浏览器的方法_一个用于监听 dom 节点尺寸变化的 Hook

    平时写项目应该经常会遇见表格动态高度适应不同屏幕和浏览器调整窗口大小的问题 一般解决办法就是使用 resize 事件来监听窗口改变 如果我要监听 textarea 的大小来做些效果 resize 事件就没办法了 因为它不能监听 DOM 的改
  • flex 初学

    flex direction 主轴的排列方向 box flex direction row row reverse column column reverse justify content 项目在主轴上的对其方式 box justify
  • 02-JVM内存模型深度剖析与优化

    一 JDK体系结构 JDK JDK提供了编译 运行Java程序所需的各种资源和工具 包括Java编译器 Java运行时环境 JRE 开发工具包括编译工具 javac exe 打包工具 jar exe 等 JRE 即JAVA运行时环境 JVM
  • Linux磁盘管理

    目录 一 建立磁盘分区 查看磁盘信息 扫盘操作 选择磁盘设备进行操作 格式化文件系统并挂载 二 LVM 逻辑卷的创建过程 1 PV Physical Volume 物理卷 2 VG Volume Group 卷组 3 LV Logical
  • 转:windows消息传递机制

    Windows是一个消息 Message 驱动系统 Windows的消息提供了应用程序之间 应用程序与Windows系统之间进行通信的手段 应用程序想要实现的功能由消息来触发 并且靠对消息的响应和处理来完成 必须注意的是 消息并非是抢占性的