int main(...)
{
printf("hello world");
printf("hello world");
}
你"猜",在内存中有几个"hello world"字符串?
int main(...)
{
printf("hello world");
printf("hello world");
}
你"猜",在内存中有几个"hello world"字符串?
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哪个效率更高?为什么
给出的解答是:
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的效率是一样的!
首先树立以下几个概念:
全局变量
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++初学者对函数调用中的引用总是感到十分迷惑
下面就研究一下
先看下面三个函数
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
引用既具有指针的效率,又具有变量使用的方便性和直观性
总体来说
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包中的文件变得既多又不好管理
作为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 例程中没有类似于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.
问题:
有时候我们希望用一个函数处理一系列的菜单命令
分析:
在处理菜单命令的函数中必须能知道菜单的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;
}
问题:
在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()
“`