C++中的逻辑运算符&&和||

a&&(b=b+2,c=c+3)
cmp DWORD PTR _a$[ebp], 0
je SHORT $L221
mov eax, DWORD PTR _b$[ebp]
add eax, 2
mov DWORD PTR _b$[ebp], eax
mov ecx, DWORD PTR _c$[ebp]
add ecx, 3
mov DWORD PTR _c$[ebp], ecx
if(a){b=b+2;c=c+3;}
cmp DWORD PTR _a$[ebp], 0
je SHORT $L221 ;&&->je
mov eax, DWORD PTR _b$[ebp]
add eax, 2
mov DWORD PTR _b$[ebp], eax
mov ecx, DWORD PTR _c$[ebp]
add ecx, 3
mov DWORD PTR _c$[ebp], ecx
a||(b=b+2,c=c+3);
cmp DWORD PTR _a$[ebp], 0
jne SHORT $L221 ;||->jne
mov eax, DWORD PTR _b$[ebp]
add eax, 2
mov DWORD PTR _b$[ebp], eax
mov ecx, DWORD PTR _c$[ebp]
add ecx, 3
mov DWORD PTR _c$[ebp], ecx

&&,||最终会被翻译成je和jne跳转
完全等价于if语句,不过当逻辑表达式作为判断条件时

if(a&&b){}

会在后面加上test eax,eax作为jmp的依据

i++,i+=1,i=i+1 哪个效率更高?

今天看到这么一道题:

i++,i+=1,i=i+1哪个效率更高?为什么

给出的解答是:

x=x+1最低,执行过程:
1)读取右边x的地址
2)x+1
3)读取左边x的地址
4)将右值给左边的x(编译器并不认为左右x的地址相同) (编译器不会这么笨吧,两个x还能有不一样的地址??)

x+=1次之,过程:
1)读取右边x的地址
2)x+1
3)将得到的值给x(因为x的地址已经读出)

x++的效率最高,过程:
1)读取右边x的地址
2)x自增1

所以x++的效率最高….

怀疑~~

不知道上面所说的过程是从什么角度来评价效率的

按我说,效率应该从产生的指令数和指令类型综合起来说

研究下列c++代码:

int
main(int,char**)
{
int i=1;
i++;
i+=1;
i=i+1;
return 0; 
}

cl.exe产生的汇编代码如下:

; Line 5
mov eax, DWORD PTR _i$[ebp]
add eax, 1
mov DWORD PTR _i$[ebp], eax
; Line 6
mov ecx, DWORD PTR _i$[ebp]
add ecx, 1
mov DWORD PTR _i$[ebp], ecx
; Line 7
mov edx, DWORD PTR _i$[ebp]
add edx, 1
mov DWORD PTR _i$[ebp], edx

g++产生的汇编代码如下:

; Line 5
leal -4(%ebp), %eax
incl (%eax)
; Line 6
leal -4(%ebp), %eax
incl (%eax)
; Line 7
leal -4(%ebp), %eax
incl (%eax)

编译器生成的汇编代码可能是经过不同成都优化的
用ollydbg查看最终exe的执行代码如下:

cl.exe产生的exe

g++产生的exe代码

可见无论cl还是g++对i++,i+=1,i=i+1的翻译都是一样的

只是cl将之翻译成3条指令,g++翻译成两条
所以说所以在上面这种情况下,i++,i+=1,i=i+1的效率是一样的!

通过汇编代码研究C++

首先树立以下几个概念:

  • 编译器 compiler
  • 链接器 linker
  • 编译时期 compile time
  • 运行时期 runtime
  • 数据段 data segment/ds
  • 代码段 code segment/cs
  • 语法 syntax
  • 语义 semantics
  • 栈 stack
  • 堆 heap

全局变量

int global_var = 5;

int
main(int argc,char** argv)
{
static int i=3;
i=7;
return 0;
}
PUBLIC          ; global_var
_DATA SEGMENT

;静态变量和全局变量在数据段分配
DD 05H          ; global_var
DD 03H
_DATA ENDS
PUBLIC _main
_TEXT SEGMENT
_main PROC NEAR
push ebp
mov ebp, esp

; 直接对数据段内存赋值
mov DWORD PTR , 7 
xor eax, eax
pop ebp
ret 0
_main ENDP
_TEXT ENDS
END

类的静态成员变量

class MyClass
{
public:
       int static       STATIC_VAR;
};

int MyClass::STATIC_VAR = 7;

int
main(int argc,char** argv)
{
MyClass::STATIC_VAR = 6;
return 0;
}
PUBLIC         ; MyClass::STATIC_VAR
_DATA SEGMENT

;类的静态成员同样在数据段分配分配内存
DD 07H         ; MyClass::STATIC_VAR
_DATA ENDS


PUBLIC _main
_TEXT SEGMENT
_main PROC NEAR
push ebp
mov ebp, esp

;直接对数据段内存赋值
mov DWORD PTR , 6 ; MyClass::STATIC_VAR
xor eax, eax
pop ebp
ret 0
_main ENDP
_TEXT ENDS
END

枚举

enum COLOR{
cl0,cl1,cl2,cl3,cl4,cl5,cl6,cl7,cl8,cl9,cl10,cl11,cl12,cl13,cl14,cl15,
cl16,cl17,cl18,cl19,cl20,cl21,cl22,cl23,cl24,cl25,cl26,cl27,cl28,cl29,cl30,
cl31,cl32,cl33,cl34,cl35,cl36,cl37,cl38,cl39,cl40,cl41,cl42,cl43,cl44,cl45,
cl46,cl47,cl48,cl49,cl50,cl51,cl52,cl53,cl54,cl55,cl56,cl57,cl58,cl59,cl60,
cl61,cl62,cl63,cl64,cl65,cl66,cl67,cl68,cl69,cl70,cl71,cl72,cl73,cl74,cl75,
cl76,cl77,cl78,cl79,cl80,cl81,cl82,cl83,cl84,cl85,cl86,cl87,cl88,cl89,cl90,
cl91,cl92,cl93,cl94,cl95,cl96,cl97,cl98,cl99,cl100,cl101,cl102,cl103,cl104,
cl105,cl106,cl107,cl108,cl109,cl110,cl111,cl112,cl113,cl114,cl115,cl116,
cl117,cl118,cl119,cl120,cl121,cl122,cl123,cl124,cl125,cl126,cl127,cl128,
cl129,cl130,cl131,cl132,cl133,cl134,cl135,cl136,cl137,cl138,cl139,cl140,
cl141,cl142,cl143,cl144,cl145,cl146,cl147,cl148,cl149,cl150,cl151,cl152,
cl153,cl154,cl155,cl156,cl157,cl158,cl159,cl160,cl161,cl162,cl163,cl164,
cl165,cl166,cl167,cl168,cl169,cl170,cl171,cl172,cl173,cl174,cl175,cl176,
cl177,cl178,cl179,cl180,cl181,cl182,cl183,cl184,cl185,cl186,cl187,cl188,
cl189,cl190,cl191,cl192,cl193,cl194,cl195,cl196,cl197,cl198,cl199,cl200,
cl201,cl202,cl203,cl204,cl205,cl206,cl207,cl208,cl209,cl210,cl211,cl212,
cl213,cl214,cl215,cl216,cl217,cl218,cl219,cl220,cl221,cl222,cl223,cl224,
cl225,cl226,cl227,cl228,cl229,cl230,cl231,cl232,cl233,cl234,cl235,cl236,
cl237,cl238,cl239,cl240,cl241,cl242,cl243,cl244,cl245,cl246,cl247,cl248,
cl249,cl250,cl251,cl252,cl253,cl254,cl255,cl256,cl257,cl258};

int
main(int argc,char** argv)
{
COLOR color = cl258;
color = cl2;
return 0;
}
PUBLIC _main
_TEXT SEGMENT
_color$ = -4
_main PROC NEAR
push ebp
mov ebp, esp
push ecx

; 枚举类型最终是以无符号整数实现的
; COLOR color = cl258;
mov DWORD PTR _color$[ebp], 258

; color = cl2;
mov DWORD PTR _color$[ebp], 2

xor eax, eax
mov esp, ebp
pop ebp
ret 0
_main ENDP
_TEXT ENDS
END

类的构造函数

class MyClass
{
public:
     int i;
     int j;
     int k;
     MyClass();
     ~MyClass();
     void f(int i);
};
MyClass::MyClass(){
this->i=7;
this->j=9;
this->k=11;
}
MyClass::~MyClass(){}
void MyClass::f(int j)
{
this->j = j;
__asm{
     mov this,5
}
}

int
main(int argc,char** argv)
{
MyClass *my = new MyClass();
my->f(3);
return 0;
}
;-----------------------------------------------
; MyClass::MyClass
;-----------------------------------------------
PUBLIC        ; MyClass::MyClass
_TEXT SEGMENT
_this$ = -4
PROC NEAR       ; MyClass::MyClass

push ebp
mov ebp, esp
push ecx
mov DWORD PTR _this$[ebp], ecx
mov eax, DWORD PTR _this$[ebp]
mov DWORD PTR [eax], 7
mov ecx, DWORD PTR _this$[ebp]
mov DWORD PTR [ecx+4], 9
mov edx, DWORD PTR _this$[ebp]
mov DWORD PTR [edx+8], 11      ; 0000000bH
mov eax, DWORD PTR _this$[ebp]
mov esp, ebp
pop ebp
ret 0
ENDP        ; MyClass::MyClass
_TEXT ENDS


;-----------------------------------------------
; MyClass::~MyClass
;-----------------------------------------------
PUBLIC        ; MyClass::~MyClass
_TEXT SEGMENT
_this$ = -4
PROC NEAR       ; MyClass::~MyClass
push ebp
mov ebp, esp
push ecx
mov DWORD PTR _this$[ebp], ecx
mov esp, ebp
pop ebp
ret 0
ENDP        ; MyClass::~MyClass
_TEXT ENDS


;-----------------------------------------------
; MyClass::f()
;-----------------------------------------------
PUBLIC        ; MyClass::f
_TEXT SEGMENT
_j$ = 8
_this$ = -4
PROC NEAR       ; MyClass::f
push ebp
mov ebp, esp
push ecx
push ebx
push esi
push edi
mov DWORD PTR _this$[ebp], ecx
mov eax, DWORD PTR _this$[ebp]
mov ecx, DWORD PTR _j$[ebp]
mov DWORD PTR [eax+4], ecx
mov DWORD PTR _this$[ebp], 5
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
ret 4
ENDP       ; MyClass::f
_TEXT ENDS


;-----------------------------------------------
; 主函数
;-----------------------------------------------
PUBLIC _main

;new操作符号就是一个函数
EXTRN        ; operator new
_TEXT SEGMENT
_my$ = -4
$T254 = -8
_main PROC NEAR
; Line 27
push ebp
mov ebp, esp
sub esp, 12
; MyClass *my = new MyClass();

; 调用new()在堆中分配一块内存,大小为MyClass左右成员变量大小之和,this指针在计算之内
; 12入栈,12是new的参数,由于编译时期MyClass已知,所以掉用new的时候不用给出参数,由编译器自己计算
push 12
call        ; operator new
add esp, 4

; new()将在堆中分配的内存块的首地址放在EAX,然后将EAX中的内容(首地址)放入变量my中
mov DWORD PTR $T254[ebp], eax

; 检查new()是否分配失败,如果失败则跳转到$L255
cmp DWORD PTR $T254[ebp], 0
je SHORT $L255

; 如果分配成功,以new()返回的首地址为参数调用MyClass的构造函数
mov ecx, DWORD PTR $T254[ebp]
call       ; MyClass::MyClass
mov DWORD PTR -12+[ebp], eax
jmp SHORT $L256
mov DWORD PTR -12+[ebp], 0
mov eax, DWORD PTR -12+[ebp]
mov DWORD PTR _my$[ebp], eax
; my->f(3);
push 3
mov ecx, DWORD PTR _my$[ebp]
call       ; MyClass::f


xor eax, eax
mov esp, ebp
pop ebp
ret 0
_main ENDP

指针和地址

int main(int argc, char *argv[])
{
int i=7;
char c = 'c';
int *pi=&i; 
char *pc=&c;
pi = (int*)pc;

return 0;
}
PUBLIC _main
_TEXT SEGMENT
_i$ = -12
_c$ = -8
_pi$ = -4
_pc$ = -16
_main PROC NEAR

push ebp
mov ebp, esp
sub esp, 16

; int i = 7;
mov DWORD PTR _i$[ebp], 7

; char c = "c";
mov BYTE PTR _c$[ebp], 99

; int *pi = &i;
lea eax, DWORD PTR _i$[ebp]
mov DWORD PTR _pi$[ebp], eax

; char *pc = &c;
lea ecx, DWORD PTR _c$[ebp]
mov DWORD PTR _pc$[ebp], ecx

; pi = (int*)pc; 
mov edx, DWORD PTR _pc$[ebp]
mov DWORD PTR _pi$[ebp], edx

xor eax, eax
mov esp, ebp
pop ebp
ret 0
_main ENDP
_TEXT ENDS
END

更新:
推荐下面这本书,对理解c++如何实现各种语言特性很有帮助

[C++反汇编与逆向分析技术揭秘](https://book.douban.com/subject/6849800/)

C++函数调用中的引用和指针

C++初学者对函数调用中的引用总是感到十分迷惑

下面就研究一下

先看下面三个函数

void f1(int a,intb) //按值传递
{
     a=0;
     b=3;
}

void f2(int &a,int &b) //按引用传递
{
     a=0;
     b=3;
}

void f3(int *a,int *b) //按指针传递
{
     *a=0;
     *b=3;
}

要想知道他们之间的区别,最好的方法是看看编译器究竟干了什么
用cl.exe 的-Fa参数,生成对应源代码的汇编代码,摘要如下

按值传递

PROC NEAR 
push ebp
mov ebp, esp
;直接将压入栈的2个参数赋值为0和3
mov DWORD PTR _a$[ebp], 0
mov DWORD PTR _b$[ebp], 3
pop ebp
ret 0

按引用传递

PROC NEAR

push ebp
mov ebp, esp
;将压入栈的参数作为指针,将0和3赋值给指针所指向的内存单元
mov eax, DWORD PTR _a$[ebp]
mov DWORD PTR [eax], 0
mov ecx, DWORD PTR _b$[ebp]
mov DWORD PTR [ecx], 3
pop ebp
ret 0

按指针传递

PROC NEAR

push ebp
mov ebp, esp
;可以看到,按引用传递和按指针传递的汇编代码一模一样
;但是使用引用,我们不必再用星号解引用了,这样提高了代码的可读性
;语言层面,引用的用法和对象一样;在二进制层面,引用一般都是通过指针来实现的,
;只不过编译器帮我们完成了转换
mov eax, DWORD PTR _a$[ebp]
mov DWORD PTR [eax], 0
mov ecx, DWORD PTR _b$[ebp]
mov DWORD PTR [ecx], 3
pop ebp
ret 0

引用既具有指针的效率,又具有变量使用的方便性和直观性

C++、Java、Delphi类继承的对比

总体来说

  • c++: 完全的控制,极大的灵活性,灵活带来的复杂
  • java:比c++"保守",虚拟机风格的体系结构
  • delphi:很保守

inclusion/using clause

#include <iostream>
using namespace std;
import java.io.*;
uses windows,system,sysutils;

inheritance
class Child:[public | protected | private] Fahter,public Mother{
            ...
}

C++是这三种语言中继承最为复杂的.
分为 public,protected,private继承,同时支持真正的多继承

public继承(又称类型继承)和java的继承一样,保持父类的访问控制

protected继承将父类public成员改变为protected的

private继承(又称实现继承)不直接支持父类的公有接口,而提供自己的公有接口

所以private继承中,子类将父类中原先的protected成员和public成员都置为private的
所以原则上private继承中的子类应该是继承树中的叶节点,它只有private和public成员而
没有protected成员.它不应该再被继承,类似于Java中的final class

class Child extends Father implements IInterface{
            ...
}
TChild = class(TFather,IInterfacedObject)
            ...
end;

java 和 delphi 的继承相似,都是单继承同时可以实现多个接口

Access Control/Organization

class Foo{
   private:
    int i;
             int j;
             void f();
   protected: 
             int k;
   public: 
             int o;
}

class Foo /* extends Object */ {
  private
             int i;
             int j;
             void f(){...};
   protected
             int k;
   public
             int o;
}
TFoo = class(TObject)
   private 
             i:Integer;
             j:Integer;
   protected
             k:Integer;
   public
             o:Integer;
   publicshed
   property
             Tag:Integer read i write i;
end;

如果不给出访问控制,
c++默认是private
java默认是包内可见的
delphi默认是public的(单元内可见?)

c++的访问控制和代码管理最为丰富:
可以通过#include包含c/cpp头文件,提供向c的兼容
同时可以使用名字空间防止名字冲突,并且像c一样将代码分为头文件和实现文件
同时丰富性也带来了复杂性.使得c++的文件组织没有java和delphi清晰

java提供了松散的代码组织方式–包(package),而delphi提供了单元的代码组织方法
这两种组织方法相似,都是给了我们一个存放一组相关类的地方.而这个地方,在java中
是一个文件系统上的文件夹,在delphi中是一个单元文件
相比之下,我还是喜欢Delphi的组织方法:当类很多的时候java包中的文件变得既多又不好管理

MFC学习笔记#1

作为Windows的Framework需要解决的一个问题就是
消息映射 Message Mapping

Delphi中由于有编译器的支持,可以直接在用户编写的类中处理需要处理的消息:

procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;

在MFC中就比较复杂了. afx使用宏来实现Windows消息到处理函数的映射而没有使用会带
而外的开销:由于C++中实现虚函数需要一个分发表vtable,而无论子类是否重写父类的虚函数,
都需要4个字节的开销.在CWnd类中至少要处理100个以上的消息.这样设计会带来很大的问题.

afx用一组宏将用于消息映射的数据保存在类中.大概情况是:记录该类可以处理的Windows消息,
当消息来到时,对比自己可以处理的消息列表,如果可以处理,就交给列表中记录的函数来处理.
而这个函数就是我们自己些的.比如 OnLButtonDown等

afx.h 中声明了mfc中最基础的类

struct CRuntimeClass;                  // object type information

class CObject;                                // the root of all objects classes

class CException;                         // the root of all exceptions
          class CArchiveException;              // archive exception
          class CFileException;                 // file exception
          class CSimpleException;
           class CMemoryException;               // out-of-memory exception
           class CNotSupportedException; // feature not supported exception

class CFile;                              // raw binary file
          class CStdioFile;                     // buffered stdio text/binary file
          class CMemFile;                       // memory based file

// Non CObject classes
class CString;                                // growable string type
class CTimeSpan;                              // time/date difference
class CTime;                                  // absolute time/date
struct CFileStatus;                           // file status information
struct CMemoryState;                          // diagnostic memory support

class CArchive;                               // object persistence tool
class CDumpContext;                           // object diagnostic dumping

先看一下CRuntimeClass

struct CRuntimeClass
{
// Attributes
LPCSTR m_lpszClassName;//保存类名
int m_nObjectSize;//类对象大小
UINT m_wSchema; // schema number of the loaded class//是否可序列化
CObject* (PASCAL* m_pfnCreateObject)(); // 指向类的构造函数的指针

           //指向父类CRuntimeClass的指针
#ifdef _AFXDLL
CRuntimeClass* (PASCAL* m_pfnGetBaseClass)();
#else
CRuntimeClass* m_pBaseClass;
#endif

// Operations
CObject* CreateObject(); //动态创建
BOOL IsDerivedFrom(const CRuntimeClass* pBaseClass) const; //类型鉴别

// Implementation
void Store(CArchive& ar) const; //序列化
static CRuntimeClass* PASCAL Load(CArchive& ar, UINT* pwSchemaNum) ;//"反序列化"

// CRuntimeClass objects linked together in simple list
CRuntimeClass* m_pNextClass;               // linked list of registered classes //注册类列表
};

CRuntimeClass 是MFC中很重要的一个类,动态创建实例是最常用的功能之一

// Helper macros for declaring CRuntimeClass compatible classes

#ifdef _AFXDLL
#define DECLARE_DYNAMIC(class_name) 
protected: 
static CRuntimeClass* PASCAL _GetBaseClass(); 
public: 
static const AFX_DATA CRuntimeClass class##class_name; 
virtual CRuntimeClass* GetRuntimeClass() const; 

#define _DECLARE_DYNAMIC(class_name) 
protected: 
static CRuntimeClass* PASCAL _GetBaseClass(); 
public: 
static AFX_DATA CRuntimeClass class##class_name; 
virtual CRuntimeClass* GetRuntimeClass() const; 

#else
#define DECLARE_DYNAMIC(class_name) 
public: 
static const AFX_DATA CRuntimeClass class##class_name; 
virtual CRuntimeClass* GetRuntimeClass() const; 

#define _DECLARE_DYNAMIC(class_name) 
public: 
static AFX_DATA CRuntimeClass class##class_name; 
virtual CRuntimeClass* GetRuntimeClass() const; 

#endif

// not serializable, but dynamically constructable
#define DECLARE_DYNCREATE(class_name) 
DECLARE_DYNAMIC(class_name) 
static CObject* PASCAL CreateObject();

#define _DECLARE_DYNCREATE(class_name) 
_DECLARE_DYNAMIC(class_name) 
static CObject* PASCAL CreateObject();

#define DECLARE_SERIAL(class_name) 
_DECLARE_DYNCREATE(class_name) 
AFX_API friend CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb);

CObject
基本服务:

BOOL IsSerializable() const;
BOOL IsKindOf(const CRuntimeClass* pClass) const; //类型鉴别

// Overridables
virtual void Serialize(CArchive& ar); //序列化

// Diagnostic Support //诊断支持
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;

//动态创建,利用CRuntimeClass里的m_pfnCreateObject
CObject* CRuntimeClass::CreateObject()

CWnd 在afxwin.h中定义,在wincore.cpp中实现
CWnd封装的功能

// Window tree access
// Message Functions
// Message processing for modeless dialog-like windows
// Window Text Functions
// CMenu Functions - non-Child windows only
// Window Size and Position Functions
// Coordinate Mapping Functions
// Update/Painting Functions
// Timer Functions
// ToolTip Functions
// Window State Functions
// Dialog-Box Item Functions
// Scrolling Functions
// Window Access Functions
// Alert Functions
// Clipboard Functions
// Caret Functions
// Shell Interaction Functions
// Icon Functions
// Context Help Functions
// Dialog Data support
// Help Command Handlers
// Layout and other functions
// OLE control wrapper functions

/* 消息处理函数 */
// Window-Management message handler member functions
// Nonclient-Area message handler member functions
// System message handler member functions
// Input message handler member functions
// Initialization message handler member functions
// Clipboard message handler member functions
// Control message handler member functions
// MDI message handler member functions
// Menu loop notification messages

Windows 控件的实现文件在 winctrl1.cpp~winctrl7.cpp

在Delphi中使用MSVC函数

在Delphi 例程中没有类似于C中的system函数

int system(const char* command);

用下面的方法可以让你在Delphi中使用msvc runtime的函数

program YourProg;
function system(command:PChar):Integer;cdecl;external "msvcrt.dll" name "system";
begin
    system("pause");
end.

在MFC中使用ON_COMMAND_EX_RANGE宏

问题:
有时候我们希望用一个函数处理一系列的菜单命令

分析:
在处理菜单命令的函数中必须能知道菜单的ID;
以前用过ON_COMMANDRANGE宏;
在afxmsg
.h中发现有个ON_COMMAND_EX宏;

解决:

BEGIN_MESSAGE_MAP(CClassName, CBaseClass)
   ...
ON_COMMAND_EX_RANGE(ID_MENUITEM_FIRST,ID_MENUITEM_FIRST, OnMenuItemClicked)
...
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

因为

#define ON_COMMAND_EX_RANGE(id, idLast, memberFxn) 
{ WM_COMMAND, CN_COMMAND, (WORD)id, (WORD)idLast, AfxSig_bw, 
   (AFX_PMSG)(BOOL (AFX_MSG_CALL CCmdTarget::*)(UINT))&memberFxn },

而且

enum AfxSig{
   ...
    AfxSig_bw = AfxSig_bb,       // BOOL (UINT)
   ...
}

所以

BOOL CClassName::OnMiWlToSubDesk(UINT nID) 
{
   int nMenuIndex = nID - ID_MENUITEM_FIRST;
   return TRUE;
}

VC中响应未定义的消息

问题:
在MFC程序中需要响应显示器分辨率变化

分析:
如果分辨率变化会产生消息并发送给所有程序,那么只要响应该消息就可以了

解决:
通过在winuser.h中搜索DISPLAY找到

#define WM_DISPLAYCHANGE                 0x007E

由于VC的ClassWizard无法自动生成响应处理该消息的成员函数,
所以要手工增加消息映射

在afxmsg_.h中找到

#define ON_MESSAGE(message, memberFxn) 
{ message, 0, 0, 0, AfxSig_lwl, 
   (AFX_PMSG)(AFX_PMSGW) 
   (static_cast< LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM) > 
   (memberFxn)) },

所以可以在相应的类中增加消息映射和函数:

函数:

// Generated message map functions
//{{AFX_MSG(CNuTsWMDlg)
virtual BOOL OnInitDialog();
...
afx_msg void OnDislayChanged(WPARAM wParam,LPARAM lParam);
...
//}}AFX_MSG
DECLARE_MESSAGE_MAP()

消息映射:
“c++
BEGIN_MESSAGE_MAP(CNuTsWMDlg, CDialog)
//{{AFX_MSG_MAP(CNuTsWMDlg)

ON_MESSAGE(WM_DISPLAYCHANGE,OnDislayChanged)

//}}AFX_MSG_MAP
END_MESSAGE_MAP()
“`

Posts navigation

1 2
Scroll to top