MFC六大关键技术之(五)(六)——消息映射与命令传递

消息映射 阅读详情

MFC六大关键技术之(五)(六)——消息映射与命令传递

题外话:刚开始学视窗程序设计的时候,我就打印了一本Windows消息详解,里面列举了各种已定义消息的意义和作用,共10多页,在编程的时候翻翻,有时觉得很受用。我发觉很多编程的朋友,虽然每天都面对消息,却很少关注它。C++程序员有一个通病,很想写“自己”的程序,即每一行代码都想自己写出来。如果用了一些库,总希望能完全理解库里的类或函数是怎么一回事,否则就“不踏实”。对于消息,许多朋友只关心常用的几个,对其余的漠不关心。其实,Windows中有很多不常用的消息却很有用,程序员可能通过响应这些消息实现更简捷的编程。

说到消息,在MFC中,“最熟悉的神秘”可算是消息映射,那是我们刚开始接触MFC时就要面对的东西。有过SDK编程经验的朋友转到MFC编程的时候,一下子觉得什么都变了样。特别是窗口消息及对消息的处理跟以前相比,更是风马牛不相及的。如文档不是窗口,是怎样响应命令消息的呢?

初次用MFC编程,我们只会用MFC ClassWizard为我们做大量的东西,最主要的是添加消息响应。记忆中,如果是自已添加消息响应,我们应何等的小心翼翼,对BEGIN_MESSAGE_MAP()……END_MESSAGE_MAP()更要奉若神灵。它就是一个魔盒子,把我们的咒语放入恰当的地方,就会发生神奇的力量,放错了,自己的程序就连“命”都没有。

据说,知道得太多未必是好事。我也曾经打算不去理解这神秘的区域,觉得编程的时候知道自己想做什么就行了。MFC外表上给我们提供了东西,直观地说,不但给了我个一个程序的外壳,更给我们许多方便。微软的出发点可能是希望达到“傻瓜编程”的结果,试想,谁不会用ClassWizard?大家知道,Windows是基于消息的,有了ClassWizard,你又会添加类,又会添加消息,那么你所学的东西似乎学到头了。于是许多程序员认为“我们没有必要走SDK的老路,直接用MFC编程,新的东西通常是简单、直观、易学……”

到你真正想用MFC编程的时候,你会发觉光会ClassWizard的你是多么的愚蠢。MFC不是一个普通的类库,普通的类库我们完全可以不理解里面的细节,只要知道这些类库能干什么,接口参数如何就万事大吉。如string类,操作顺序是定义一个string对象,然后修改属性,调用方法。

但对于MFC,你并不是在你的程序中写上一句“#include MFC.h”,然后就在你的程序中用MFC类库。

MFC是一块包着糖衣的牛骨头。你很轻松地写出一个单文档窗口,在窗口中间打印一句“I love MFC!”,然后,恶梦开始了……想逃避,打算永远不去理解MFC内幕?门都没有!在MFC这个黑暗神秘的洞中,即使你打算摸着石头前行,也注定找不到出口。对着MFC这块牛骨头,微软温和、民主地告诉你“你当然可以选择不啃掉它,咳咳……但你必然会因此而饿死!”

消息映射与命令传递体现了MFC与SDK的不同。在SDK编程中,没有消息映射的概念,它有明确的回调函数中,通过一个switch语句去判断收到了何种消息,然后对这个消息进行处理。所以,在SDK编程中,会发送消息和在回调函数中处理消息就差不多可以写SDK程序了。

在MFC中,看上去发送消息和处理消息比SDK更简单、直接,但可惜不直观。举个简单的例子,如果我们想自定义一个消息,SDK是非常简单直观的,用一条语句:SendMessage(hwnd,message/*一个大于或等于WM_USER的数字*/,wparam,lparam),之后就可以在回调函数中处理了。但MFC就不同了,因为你通常不直接去改写窗口的回调函数,所以只能亦步亦趋对照原来的MFC代码,把消息放到恰当的地方。这确实是一样很痛苦的劳动。

要了解MFC消息映射原理并不是一件轻松的事情。我们可以逆向思维,想象一下消息映射为我们做了什么工作。MFC在自动化给我们提供了很大的方便,比如,所有的MFC窗口都使用同一窗口过程,即所有的MFC窗口都有一个默认的窗口过程。不象在SDK编程中,要为每个窗口类写一个窗口过程。

对于消息映射,最直截了当地猜想是:消息映射就是用一个数据结构把“消息”与“响应消息函数名”串联起来。这样,当窗口感知消息发生时,就对结构查找,找到相应的消息响应函数执行。其实这个想法也不能简单地实现:我们每个不同的MFC窗口类,对同一种消息,有不同的响应方式。即是说,对同一种消息,不同的MFC窗口会有不同的消息响应函数。

这时,大家又想了一个可行的方法。我们设计窗口基类(CWnd)时,我们让它对每种不同的消息都来一个消息响应,并把这个消息响应函数定义为空虚函数。这样,从CWnd派生的窗口类对所有消息都有了一个空响应,我们要响应一个特定的消息就重载这个消息响应函数就可以了。但这样做的结果,一个几乎什么也不做的CWnd类要有几百个“多余”的函数,那怕这些消息响应函数都为纯虚函数,每个CWnd对象也要背负着一个巨大的虚拟表,这也是得不偿失的。

许多朋友在学习消息映射时苦无突破,其原因是一开始就认为MFC的消息映射的目的是为了替代SDK窗口过程的编写——这本来没有理解错。但他们还有多一层的理解,认为既然是替代“旧”的东西,那么MFC消息映身应该是更高层次的抽象、更简单、更容易认识。但结果是,如果我们不通过ClassWizard工具,手动添加消息是相当迷茫的一件事。

所以,我们在学习MFC消息映射时,首先要弄清楚:消息映射的目的,不是为是更加快捷地向窗口过程添加代码,而是一种机制的改变。如果不想改变窗口过程函数,那么应该在哪里进行消息响应呢?许多朋友一知半解地认为:我们可以用HOOK技术,抢在消息队列前把消息抓取,把消息响应提到窗口过程的外面。再者,不同的窗口,会有不同的感兴趣的消息,所以每个MFC窗口都应该有一个表把感兴趣的消息和相应消息响应函数连系起来。然后得出——消息映射机制执行步骤是:当消息发生,我们用HOOK技术把本发送到窗口过程的消息抓获,然后对照一下MFC窗口的消息映射表,如果是表里面有的消息,就执行其对应的函数。

当然,用HOOK技术,我们理论上可以在不改变窗口过程函数的情况下,可以完成消息响应。MFC确实是这样做,但实际操作起来可能跟你的想象差别很大。

现在我们来编写消息映射表,我们先定义一个结构,这个结构至少有两个项:一是消息ID,二是响应该消息的函数。如下:

struct AFX_MSGMAP_ENTRY

{

UINT nMessage;           //感兴趣的消息

AFX_PMSG pfn;          //响应以上消息的函数指针

}

当然,只有两个成员的结构连接起来的消息映射表是不成熟的。Windows消息分为标准消息、控件消息和命令消息,每类型的消息包含数百不同ID、不同意义、不同参数的消息。我们要准确地判别发生了何种消息,必须再增加几个成员。还有,对于AFX_PMSG pfn,实际上等于作以下声明:

void (CCmdTarget::*pfn)();

(提示:AFX_PMSG为类型标识,具体声明是:typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void);)

pfn是不一不带参数和返回值的CCmdTarget类型函数指针,只能指向CCmdTarget类中不带参数和返回值的成员函数,这样pfn更为通用,但我们响应消息的函数许多需要传入参数的。为了解决这个矛盾,我们还要增加一个表示参数类型的成员。当然,还有其它……

最后,MFC消息映射表成员结构如下定义:

struct AFX_MSGMAP_ENTRY

{

UINT nMessage;           //Windows 消息ID

UINT nCode;                // 控制消息的通知码

UINT nID;                   //命令消息ID范围的起始值

UINT nLastID;             //命令消息ID范围的终点

UINT nSig;                   // 消息的动作标识

AFX_PMSG pfn;

};

 

AFX_MSGMAP_ENTRY _messageEntries[];

 

为了能查找各MFC对象下的消息映射表,我们还要增加一个结构,把所有的AFX_MSGMAP_ENTRY数组串联起来。

于是,我们定义了一个新结构体:

struct AFX_MSGMAP

{

const AFX_MSGMAP* pBaseMap;                   //指向别的类的AFX_MSGMAP对象

const AFX_MSGMAP_ENTRY* lpEntries;       //指向自身的消息表

};

之后,在每个打算响应消息的类中这样声明一个变量:AFX_MSGMAP messageMap,让其中的pBaseMap指向基类或另一个类的messageMap,那么将得到一个AFX_MSGMAP元素的单向链表。这样,所有的消息映射信息形成了一张消息网。

有了以上消息映射表成员结构,我们就可以定义一个AFX_MSGMAP_ENTRY类型的数组,用来容纳消息映射项。定义如下: 但这样还不够,每个AFX_MSGMAP_ENTRY数组,只能保存着当前类感兴趣的消息,而这仅仅是我们想处理的消息中的一部分。对于一个MFC程序,一般有多个窗口类,里面都应该有一个AFX_MSGMAP_ENTRY数组。我们知道,MFC 还有一个消息传递机制,可以把自己不处理的消息传送给别的类进行处理。

当然,仅有消息映射表还不够,它只能把各个MFC对象的消息、参数与相应的消息响应函数连成一张网。为了方便查找,MFC在上面的类中插入了两个函数(其中theClass代表当前类):

一个是_GetBaseMessageMap(),用来得到基类消息映射的函数。函数原型如下:

const AFX_MSGMAP* PASCAL theClass::_GetBaseMessageMap() /

{ return &baseClass::messageMap; } /

别一个是GetMessageMap() ,用来得到自身消息映射的函数。函数原型如下:

const AFX_MSGMAP* theClass::GetMessageMap() const /

{ return &theClass::messageMap; } /

 

有了消息映射表之后,我们得讨论到问题的关键,那就是消息发生以后,其对应的响应函数如何被调用。大家知道,所有的MFC窗口,都有一个同样的窗口过程——AfxWndProc(…)。在这里顺便要提一下的是,看过MFC源代码的朋友都得,从AfxWndProc函数进去,会遇到一大堆曲折与迷团,因为对于这个庞大的消息映射机制,MFC要做的事情很多,如优化消息,增强兼容性等,这一大量的工作,有些甚至用汇编语言来完成,对此,我们很难深究它。所以我们要省略大量代码,理性地分析它。

对已定型的AfxWndProc来说,对所有消息,最多只能提供一种默认的处理方式。这当然不是我们想要的。我们想通过AfxWndProc最终执行消息映射网中对应的函数。那么,这个执行路线是怎么样的呢?

从AfxWndProc下去,最终会调用到一个函数OnWndMsg。请看代码:

LRESULT CALLBACK AfxWndProc(HWND hWnd,UINT nMsg,WPARAM wParam, LPARAM lParam)

{    

……

       CWnd* pWnd = CWnd::FromHandlePermanent(hWnd); //把对句柄的操作转换成对CWnd对象。

       Return AfxCallWndProc(pWnd,hWnd,nMsg,wParam,lParam);

}

把对句柄的操作转换成对CWnd对象是很重要的一件事,因为AfxWndProc只是一个全局函数,当然不知怎么样去处理各种windows窗口消息,所以它聪明地把处理权交给windows窗口所关联的MFC窗口对象。

现大,大家几乎可以想象得到AfxCallWndProc要做的事情,不错,它当中有一句:

pWnd->WindowProc(nMsg,wParam,lParam);

到此,MFC窗口过程函数变成了自己的一个成员函数。WindowProc是一个虚函数,我们甚至可以通过改写这个函数去响应不同的消息,当然,这是题外话。

WindowProc会调用到CWnd对象的另一个成员函数OnWndMsg,下面看看大概的函数原形是怎么样的:

BOOL CWnd::OnWndMsg(UINT message,WPARAM wParam,LPARAM lParam,LRESULT* pResult)

       {

              if(message==WM_COMMAND)

                     {

                            OnCommand(wParam,lParam);

……

}

              if(message==WM_NOTIFY)

                     {

                            OnCommand(wParam,lParam,&lResult);

……

}

const AFX_MSGMAP* pMessageMap; pMessageMap=GetMessageMap();

const AFX_MSGMAP_ENTRY* lpEntry;

/*以下代码作用为:用AfxFindMessageEntry函数从消息入口pMessageMap处查找指定消息,如果找到,返回指定消息映射表成员的指针给lpEntry。然后执行该结构成员的pfn所指向的函数*/     if((lpEntry=AfxFindMessageEntry(pMessageMap->lpEntries,message,0,0)!=NULL)

{

           lpEntry->pfn();/*注意:真正MFC代码中没有用这一条语句。上面提到,不同的消息参数代表不同的意义和不同的消息响应函数有不同类型的返回值。而pfn是一个不带参数的函数指针,所以真正的MFC代码中,要根据对象lpEntry的消息的动作标识nSig给消息处理函数传递参数类型。这个过程包含很复杂的宏代换,大家在此知道:找到匹配消息,执行相应函数就行!*/

}

}

                    

以上,大家看到了OnWndMsg能根据传进来的消息参数,查找到匹配的消息和执行相应的消息响应。但这还不够,我们平常响应菜单命令消息的时候,原本属于框架窗口(CFrameWnd)的WM_COMMAND消息,却可以放到视对象或文档对象中去响应。其原理如下:

我们看上面函数OnWndMsg原型中看到以下代码:

if(message==WM_COMMAND)

                     {

                            OnCommand(wParam,lParam);

……

}

即对于命令消息,实际上是交给OnCommand函数处理。而OnCommand是一个虚函数,即WM_COMMAND消息发生时,最终是发生该消息所对应的MFC对象去执行OnCommand。比如点框架窗口菜单,即向CFrameWnd发送一个WM_COMMAND,将会导致CFrameWnd::OnCommand(wParam,lParam)的执行。

且看该函数原型

BOOL CFrameWnd::OnCommand(WPARAM wParam,LPARAM lParam)

{

       ……

       return CWnd:: OnCommand(wParam,lParam);

}

可以看出,它最后把该消息交给CWnd:: OnCommand处理。再看:

BOOL CWnd::OnCommand(WPARAM wParam,LPARAM lParam)

{

       ……

       return OnCmdMsg(nID,nCode,NULL,NULL);

}

这里包含了一个C++多态性很经典的问题。在这里,虽然是执行CWnd类的函数,但由于这个函数在CFrameWnd:: OnCmdMsg里执行,即当前指针是CFrameWnd类指针,再有OnCmdMsg是一个虚函数,所以如果CFrameWnd改写了OnCommand,程序会执行CFrameWnd::OnCmdMsg(…)。

对CFrameWnd::OnCmdMsg(…)函数原理扼要分析如下:

BOOL CFrameWnd:: OnCmdMsg(…)

{

       CView pView = GetActiveView();//得到活动视指针。

       if(pView-> OnCmdMsg(…))

       return TRUE; //如果CView类对象或其派生类对象已经处理该消息,则返回。

       ……//否则,同理向下执行,交给文档、框架、及应用程序执行自身的OnCmdMsg。

}

到此,CFrameWnd:: OnCmdMsg完成了把WM_COMMAND消息传递到视对象、文档对象及应用程序对象实现消息响应。

写了这么多,我们清楚MFC消息映射与命令传递的大致过程。现在,我们来看MFC“神秘代码”,会发觉好看多了。

先看DECLARE_MESSAGE_MAP()宏,它在MFC中定义如下:

#define DECLARE_MESSAGE_MAP() /

private: /

       static const AFX_MSGMAP_ENTRY _messageEntries[]; /       

protected: /

       static AFX_DATA const AFX_MSGMAP messageMap; /

       virtual const AFX_MSGMAP* GetMessageMap() const; /

 

 

现在集中精力来看一下BEGIN_MESSAGE_MAP,END_MESSAGE_MAP和ON_COMMAND三个宏,它们在MFC中定义如下(其中ON_COMMAND与另外两个宏并没有定义在同一个文件中,把它放到一起是为了好看):

#define BEGIN_MESSAGE_MAP(theClass, baseClass) /

const AFX_MSGMAP* theClass::GetMessageMap() const /

{ return &theClass::messageMap; } /

AFX_COMDAT AFX_DATADEF const AFX_MSGMAP theClass::messageMap = /

{ &baseClass::messageMap, &theClass::_messageEntries[0] }; /

AFX_COMDAT const AFX_MSGMAP_ENTRY theClass::_messageEntries[] = /

{ /

 

#define ON_COMMAND(id, memberFxn) /

       { WM_COMMAND, CN_COMMAND, (WORD)id, (WORD)id, AfxSig_vv, (AFX_PMSG)&memberFxn },

 

#define END_MESSAGE_MAP() /

{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } /

}; /

 

一下子看三个宏觉得有点复杂,但这仅仅是复杂,公式性的文字代换并不是很难。且看下面例子,假设我们框架中有一菜单项为“Test”,即定义了如下宏:

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)

      ON_COMMAND(ID_TEST, OnTest)

END_MESSAGE_MAP()

 

那么宏展开之后得到如下代码:

const AFX_MSGMAP* CMainFrame::GetMessageMap() const

{ return &CMainFrame::messageMap; }

///以下填入消息表映射信息

const AFX_MSGMAP CMainFrame::messageMap =         

{ &CFrameWnd::messageMap, &CMainFrame::_messageEntries[0] };

//下面填入保存着当前类感兴趣的消息,可填入多个AFX_MSGMAP_ENTRY对象

const AFX_MSGMAP_ENTRY CMainFrame::_messageEntries[] =

{

{ WM_COMMAND, CN_COMMAND, (WORD)ID_TEST, (WORD)ID_TEST, AfxSig_vv, (AFX_PMSG)&OnTest },       //       加入的ID_TEST消息参数

{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } //本类的消息映射的结束项

};

 

大家知道,要完成ID_TEST消息映射,还要定义和实现OnTest函数。在此即要在头文件写afx_msg void OnTest()并在源文件中实现它。根据以上所学的东西,我们知道了当ID为ID_TEST的命令消息发生,最终会执行到我们写的OnTest函数。

 

至此,MFC六大关键技术写完了。其中写得最难的是消息映射与命令传递,除了技术复杂之外,最难的是有许多避不开的代码。为了大家看得轻松一点,我把那繁杂的宏放在文章最后,希望能给你阅读带来方便。

其实,较早前这就描述过MFC六大关键技术,也在一些论坛上发表过,但后三篇不知如何遗失了。许多朋友向我索稿,但苦于没有备份,也不想枯燥地重写,故推延至今,请大家见谅。

还有,许多朋友说(二)(三)写得十分不明白,这也是我意料到的地方。我写文章,很少回头看一下,有时自己也不知道自己写了什么。有许多朋友把修改后的版本给我,虽然修改了一点点,甚至仅仅修改了一下错别字,但读起来容易理解很多。对此,我内心十分感激。如果有更多的时间,我会修改一下前面的文章,放到我的网站上去! 

可以看出DECLARE_MESSAGE_MAP()定义了我们熟悉的两个结构和一个函数,显而易见,这个宏为每个需要实现消息映射的类提供了相关变量和函数。
VS2015之博大精深的MFC项目开发(一) not captured,就是当鼠标移出了对话框窗口客户区之外的时候,标题栏上的文字就不响应了(不响应鼠标移动消息了),离开窗口的话光标就无效了,光标在窗口内的话就响应鼠标移动消息,也就是说包含光标的窗口才能收到这个消息;the window that has captured the mouse,也就是把这个光标绑到这个窗口,离开窗口之后光标仍然有效。继续研究wParam参数,如何把按下左键拖动也能显示出来呢? 阅读详情

相关推荐

C++消息映射机制源代码

简介:完全不是MFC中的消息映射机制,即没有用到MFC中的一点消息机制。 但原理却是一样的,是个麻雀虽小五脏俱全的消息映射原理,简单实现了 SendMail(APPMSG_START, NULL, APPID_TEST1, 0)的源代码,经测试成功。 PostMail同理可自行实现。 现放在优快云网上供大家批评建议。可留言QQ:2765049745

信息映射

计算机不是面向问题设计的,问题也不是自然可以表达为计算模型的,在计算机与问题之间有着n层抽象,一步一步把计算设备与我们的客观的信息处理的物理经验连接起来。现实世界系统物理模型——>问题逻辑模型——>计算机逻辑模型——>计算机物理模型。这n层抽象就是n层映射,为信息处理提供坚实的逻辑基础。 转载于:https://www.cnblogs.com/jcode/p/4593534.ht...

weixin_30518397的博客 116

经典烧脑算法逻辑题--高楼扔鸡蛋:最少次数测出鸡蛋摔碎临界点。

如果在第2层没碎,换到第3层扔.......如果第59层没碎,换到第60层扔;有2个鸡蛋,从100层楼上往下扔,以此来测试鸡蛋的硬度。比如鸡蛋在第9层没有摔碎,在第10层摔碎了,那么鸡蛋不会摔碎的临界点就是9层。因此,我们尝试每10层扔一次,第一次从10层扔,第二次从20层扔,第三次从30层......一直扔到100层。如果第一枚鸡蛋,在50层碎了,第二枚鸡蛋,就从第1层开始扔,一层一层增长,一直扔到第49层。如果第一枚鸡蛋在50层没碎了,则继续使用二分法,在剩余楼层的一半(75层)往下扔。

借雨醉东风的博客 1818

MFC中消息映射与命令传递机制初探

本文主要根据侯捷《深入浅出MFC》整理而成,主要讲述MFC消息映射与传递机制。

_Santiago的博客 1705

FPGA AXI DDR3读写时序调试与FIFO缓存实战解析

本文深入解析FPGA中AXI协议与DDR3的读写时序调试,重点探讨FIFO缓存在数据流控制中的关键作用。通过实战案例详细讲解突发传输中的地址对齐、数据分片等常见问题,并提供状态机设计、仿真波形分析和性能优化技巧,帮助开发者高效解决高速数据存储场景下的时序同步与数据一致性问题。

blockchain9miner的博客 1120

Ubuntu 22.04 “软件与更新”装了NVIDIA驱动,WiFi等设备不见了

在Win10装了Ubuntu22.04的双系统,台式机里面有NVIDIA 3080Ti的独立显卡,Ubuntu默认使用的nouveau驱动,需要更换成NVIDIA相应的驱动,在软件和更新里面一键安装了NVIDIA-driver-535-server之后,发现wifi、蓝牙等设备消失了。这个问题的根源据说跟这个nouveau驱动有关,希望linux社区可以解决这个问题。命令安装后 sudo reboot就可以重新看到WiFi以及蓝牙等设备图标了。然后用U盘拷贝到不能上网的Ubuntu22.04系统上,利用。

me_ysd的博客 5855

MFC教程(4)消息映射的实现

消息映射的实现 Windows消息概述 Windows应用程序的输入由Windows系统以消息的形式发送给应用程序的窗口。这些窗口通过窗口过程来接收和处理消息,然后把控制返还给Windows。消息的分类 队列消息和非队列消息 从消息的发送途径上看,消息分两种:队列消息和非队列消息。队列消息送到系统消息队列,然后到线程消息队列;非队列消息直接送给目的窗口过程。这里,对消息队列阐述如下:Windows

3412

STM32CubeMX和华为LiteOS Studio开发STM32

传统的STM32的开发通常使用Keil/IAR这类开发软件,随着物联网时代的到来,传统嵌入式的发展不断向物联网方向靠拢,而Keil/IAR这类开发软件无法满足IoT一站式的开发,华为LiteOS Studio结合STM32CubeMX可以快速,高效地进行物联网开发,本文提供一种开发思路及环境的配置方法。...

weixin_45680600的博客 2833

MFC六大关键技术

我并不认为MFC减轻了程序员们的负担,MFC出现的目的虽然似乎是为了让程序员不用懂得太多就可以进行视窗编程,但本人在MFC里徘徊了很久很久(因为那时没有书本详细介绍MFC的原理),毫无收获。可能朋友们会说,怎么一定要了解MFC的具体呢,“黑箱”作业不行吗?这不是微软的初衷吗?

netanimals的专栏 9985

用 CDS View I_APARToleranceGroup 管理客户与供应商收付差异容差:配置语义、字段解读与 ABAP 落地实践

财务共享服务中心常面临小额差异处理的挑战,SAP通过"客户/供应商容差组"机制实现自动清账规则配置。CDS视图I_APARToleranceGroup将配置数据转化为可查询维度,包含宽限天数、固定现金折扣等关键业务参数。该视图支持按公司代码和容差组查询差异处理策略,可用于报表开发、主数据校验和接口合规检查,帮助财务团队高效管理海量小额交易差异,减少手工操作。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 130

黑猫带你学UFS协议第8篇:UFS电气特性详解(Power、CLK、Reset等)

UFS强制支持secure mode。UFS设备可能会存储个人或者公司的信息,UFS提供把数据永久从设备上移除的功能,并且保证对存储介质进行逆向恢复数据也恢复不回来原有数据。安全模式是以逻辑单元为单位进行应用的,不同的逻辑单元可以有不同的安全模式。由于UFS设备的存储介质不同,所以把数据安全从存储介质上移除方式会有不同,spec提供了三种通用的移除方法,UFS设备至少支持其中一种。● 对存储的位置进行一次擦除操作。● 对存储的位置使用单一字符(比如0xAA)覆盖写,然后进行擦除。.........

黑猫奥利奥的博客 4076

MFC六大核心机制【消息映射】

1、MFC程序的初始化。 2、运行时类型识别(RTTI)。 3、动态创建。 4、永久保存。5、消息映射。6、消息传递。 五、消息映射和命令传递 作为C++程序员,我们总是希望自己程序的所有代码都是自己写出来的,如果使用了其他的一些库,也总是千方百计想弄清楚其中的类和函数的原理,否则就会感觉不踏实。所以,我们对于在进行MFC视窗程序设计时经常要用到的消息机制也不满足于会使用,而是希望能理解个中道...

平凡 1163

026、传感器校准:加速度计校准

本文详细介绍了无人机飞控系统中加速度计的校准方法。作者从一次炸机事故引入,强调加速度计校准的重要性。文章首先解释了加速度计测量原理和误差来源,包括零偏、尺度因子和交叉轴耦合。重点介绍了两种校准方法:六位置法利用重力作为参考,操作简单但精度有限;椭球拟合通过采集大量数据点进行最小二乘拟合,精度更高但实现复杂。文章还指出温度补偿这一常被忽视的关键因素,并分享了实际调试中的经验教训,包括采样时长、安装误差、验证方法等。最后建议初学者从六位置法入手,逐步优化校准精度,强调良好的校准是飞控性能的基础。

2401_88858637的博客 45

MFC六大核心机制之五、六:消息映射和命令传递

作为C++程序员,我们总是希望自己程序的所有代码都是自己写出来的,如果使用了其他的一些库,也总是千方百计想弄清楚其中的类和函数的原理,否则就会感觉不踏实。所以,我们对于在进行MFC视窗程序设计时经常要用到的消息机制也不满足于会使用,而是希望能理解个中道理。本文就为大家剖析MFC消息映射和命令传递的原理。        理解MFC消息机制的必要性        说到消息,在MFC中,“最

天天water的专栏 4644

【制作100个unity游戏之22】3DRPG游戏开发07——其他详细的设计

我们会有有很多单例,如果每个单例都去写会很麻烦,所以我们定义泛型单例模式 Singleton,我们将所有的单例都继承这个泛型单例,就省略很多重复的工作定义一个GameManager类,继承Singleton,控制整个游戏的进度,比如如果主角死了,广播,游戏结束调用。

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 2577

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

MFC中的六大关键技术

MFC中的六大关键技术这一篇主要讲解一下MFC中的6个主要的关键技术,整个Application Framework其实从本质上来说都是建立在这6个关键技术上的。所以能够了解它们的原理对理解MFC整个框架和程序设计有非常大的好处。1、MFC程序的初始化工作在MFC中所有的类都来源于一个基类:CObject。MFC程序初始化过程中,其实就是虚函数的调用的过程,分清调用执行的到底是哪一个具体的虚函数,是父类的虚函数,还是基类的虚函数,都是至关重要的。2、RTTI运行时类型识别MFC程序运行过程中需要对类的类型进

如果这是你所爱的,要坚持,并踏实。 7193

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

MFC六大关键技术之(五六)

MFC六大关键技术之(五六)消息映射与命令传递      说到消息,在MFC中,“最熟悉的神秘”可算是消息映射,那是我们刚开始接触MFC时就要面对的东西。有过SDK编程经验的朋友转到MFC编程的时候,一下子觉得什么都变了样。特别是窗口消息及对消息的处理跟以前相比,更是风马牛不相及的。如文档不是窗口,是怎样响应命令消息的呢? 初次用MFC编程,我们只会用MFC ClassWizard

beitcoder的专栏 969

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

上一篇: MFC 教程
下一篇: MFC中消息映射机制分析
sunjd2001
博客等级 码龄20年 30粉丝 0原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值