根据ISO/IEC 14882:2003(E)对C++的标准定义来看,第15页到19页,一个integer后缀可以为:uU, fF, lL 不过,微软扩展了一些后缀:http://msdn2.microsoft.com/en-us/library/00a1awxf.aspxiN (N=8, 16, 32, 64), LL, ll 比如:-1i16, 256i32等等…… 让人疑惑的是这个iN。 对于iN的修饰的整型长度为N位,比如sizeof(0i8), sizeof(0i16), sizeof(0i32), sizeof(0i64) 的值分别为1, 2, 4, 8。 你可以将i8理解为(char), 所以 0i8 == (char)(0)。 (当然ui8就是unsigned char, 0ui8 == (unsigned char)0) 请看下面程序: int a;1)a = 256i8;2)a = char(256);3)char c = 256; a = c; 全部都是等价的操作。 那么,为什么微软要加这样一个定义呢? 来看看常用的地方: #define _I32_MIN (-2147483647i32-1) /* minimum signed… Continue reading Visual C++中int后缀i的使用
Category: Uncategorized
VC++中exe的图标(转自MSDN论坛)
The way Windows chooses the icon of the main executable file is that it looks for the first icon in the resource section of the executable, or something along these lines. First of all, you need to add a resource script, .rc file. This is done through Project->Add New Item or right click on solution explorer and go… Continue reading VC++中exe的图标(转自MSDN论坛)
synaptics触摸板在注册表中的一个设置
synaptics官方的触摸板驱动没有带上一个很有用的选项,就是当外接的鼠标插上电脑后自动禁用触摸板,其实这个功能他是本来就支持的,只是有时候没有给出菜单选项,但是我们可以通过修改注册表的方式来告诉它。 [HKEY_CURRENT_USER\Software\Synaptics\SynTPEnh]“DisableIntPDFeature”=dword:00000003 [HKEY_LOCAL_MACHINE\SOFTWARE\Synaptics\SynTPEnh]“DisableIntPDFeature”=dword:00000003
自定义文件类型的图标与打开方式
在注册表的HKEY_CLASS_ROOT根键下创建一个项叫做.fileextension,这里的fileextension换成你所要创建的文件类型,然后在这个项的默认值上填写一个字符串,比如:file1。然后再创建一个叫做file1的项,位置也是在HKEY_CLASS_ROOT下,然后对于这个项,创建一个子项叫做DefaultIcon,在其默认值中填写一个icon文件的位置,然后用逗号+数字的方式表示所需要的图标序号,如C:\a.ico,0 。 然后在DefaultIcon相同的位置建立shell/open/command项(这是三个一级级深入的项,不是一个项),在command的默认值上写用于打开的可执行文件的位置,比如:”C:\ruby\bin\ruby.exe” “%1” 如上,就可以自定义文件类型了。这里主要是讲述了图标和打开方式,其余比如右键菜单等更多内容还没有深入研究,以后如果有机会再加入。
Windows文件夹图标
创建 desktop.ini文件,写入类似内容 [.ShellClassInfo]IconFile=C:\Program Files (x86)\Axialis\IconWorkshop\axlibico.dllIconIndex=0 这里的图标文件可以包含有多个图标,然后通过 IconIndex来选择
ON_UPDATE_COMMAND_UI
在Document/View的MFC程序中,要想改变工具栏上图标的状态并不是光设置了状态就会起作用的。事实上MFC会调用ON_UPDATE_COMMAND_UI的消息来确定工具栏上图标的状态,所以需要映射这个消息的处理函数,然后在其中修改图标状态。 Example: ON_UPDATE_COMMAND_UI(IDT_START_DEBUG, OnUpdateToolBarUI) void CMainFrame::OnUpdateToolBarUI( CCmdUI* pUI ){ switch(m_state.state) { case 0: case 1: pUI->Enable(TRUE); break; case 2: pUI->Enable(TRUE); break; case 3: pUI->Enable(FALSE); break; } }
静态对象、全局对象与程序的运行机制
1、在介绍静态对象、全局对象与程序的运行机制之间的关系之前,我们首先看一下atexit函数。atexit函数的声明为:int atexit( void ( __cdecl *func )( void ) ); 参数为函数指针,返回值为整型,0表示成功,其他表示失败。当程序运行结束时,他调用atexit函数注册的所有函数。如果多次调用atexit函数,那么系统将以LIFO(list-in-first-out)的方式调用所有的注册函数。 举例如下(代码摘自MSDN): #include <stdlib.h>#include <stdio.h>void fn1( void ), fn2( void ), fn3( void ), fn4( void ); void main( void ){ atexit( fn1 ); atexit( fn2 ); atexit( fn3 ); atexit( fn4 ); printf( “This is executed first.\n” );}void fn1(){ printf( “next.\n” );} void fn2(){ … Continue reading 静态对象、全局对象与程序的运行机制
MFC关键技术(3)
三、动态创建 动态创建就是运行时创建指定类的对象,在MFC中大量使用。如框架窗口对象、视对象,还有文档对象都需要由文档模板类对象来动态的创建。我觉得这是每个MFC的学习者很希望理解的问题。 初次接触MFC的时候,很容易有这样的迷惘。MFC的几大类不用我们设计也就罢了,但最疑惑的是不用我们实例化对象。本来最直观的理解就是,我们需要框架的时候,亲手写上CFrameWnd myFrame;需要视的时候,亲自打上CView myView;…… 但MFC不给我们这个机会,致使我们错觉窗口没有实例化就弹出来了!就象画了张电视机的电路图就可以看电视一样令人难以置信。但大伙想了一下,可能会一拍脑门,认为简单不过:MFC自动帮我们完成CView myView之流的代码不就行了么!!!其实不然,写MFC程序的时候,我们几乎要对每个大类进行派生改写。换句话说,MFC并不知道我们打算怎样去改写这些类,当然也不打算全部为我们“静态”创建这些类了。即使静态了创建这些类也没有用,因为我们从来也不会直接利用这些类的实例干什么事情。我们只知道,想做什么事情就往各大类里塞,不管什么变量、方法照塞,塞完之后,我们似乎并未实例化对象,程序就可以运行! 要做到把自己的类交给MFC,MFC就用同一样的方法,把不同的类一一准确创建,我们要做些什么事情呢?同样地,我们要建立链表,记录各类的关键信息,在动态创建的时候找出这些信息,就象上一节RTTI那样!我们可以设计一个类: struct CRuntimeClass{ LPCSTR m_lpszClassName; //类名指针 CObject* (PASCAL *m_pfnCreateObject)(); //创建对象的函数的指针 CRuntimeClass* m_pBaseClass; //讲RTTI时介绍过 CRuntimeClass* m_pNextClass; //指向链表的下一个元素(许多朋友说上一节讲RTTI时并没有用到这个指针,我原本以为这样更好理解一些,因为没有这个指针,这个链表是无法连起来,而m_pBaseClass仅仅是向基类走,在MFC的树型层次结构中m_pBaseClass是不能遍历的) CObject* CreateObject(); //创建对象 static CRuntimeClass* PASCAL Load(); //遍历整个类型链表,返回符合动态创建的对象。 static CRuntimeClass* pFirstClass; //类型链表的头指针 }; 一下子往结构里面塞了那么多的东西,大家可以觉得有点头晕。至于CObject* (PASCAL *m_pfnCreateObject)();,这定义函数指针的方法,大家可能有点陌生。函数指针在C++书籍里一般被定为选学章节,但MFC还是经常用到此类的函数,比如我们所熟悉的回调函数。简单地说m_pfnCreateObject即是保存了一个函数的地址,它将会创建一个对象。即是说,以后,m_pfnCreateObject指向不同的函数,我们就会创建不同类型的对象。 有函数指针,我们要实现一个与原定义参数及返回值都相同一个函数,在MFC中定义为: static CObject* PASCAL CreateObject(){return new XXX};//XXX为类名。类名不同,我们就创建不同的对象。 由此,我们可以如下构造CRuntimeClass到链表:… Continue reading MFC关键技术(3)
MFC关键技术(2)
二、运行时类型识别(RTTI)运行时类型识别(RTTI)即是程序执行过程中知道某个对象属于某个类,我们平时用C++编程接触的RTTI一般是编译器的RTTI,即是在新版本的VC++编译器里面选用“使能RTTI”,然后载入typeinfo.h文件,就可以使用一个叫typeid()的运算子,它的地位与在C++编程中的sizeof()运算子类似的地方(包含一个头文件,然后就有一个熟悉好用的函数)。typdid()关键的地方是可以接受两个类型的参数:一个是类名称,一个是对象指针。所以我们判别一个对象是否属于某个类就可以象下面那样:if (typeid (ClassName)== typeid(*ObjectName)){((ClassName*)ObjectName)->Fun();}象上面所说的那样,一个typeid()运算子就可以轻松地识别一个对象是否属于某一个类,但MFC并不是用typeid()的运算子来进行动态类型识别,而是用一大堆令人费解的宏。很多学员在这里很疑惑,好象MFC在大部分地方都是故作神秘。使们大家编程时很迷惘,只知道在这里加入一组宏,又在那儿加入一个映射,而不知道我们为什么要加入这些东东。其实,早期的MFC并没有typeid()运算子,所以只能沿用一个老办法。我们甚至可以想象一下,如果MFC早期就有template(模板)的概念,可能更容易解决RTTI问题。所以,我们要回到“古老”的年代,想象一下,要完成RTTI要做些什么事情。就好像我们在一个新型(新型到我们还不认识)电器公司里面,我们要识别哪个是电饭锅,哪个是电磁炉等等,我们要查看登记的各电器一系列的信息,我们才可以比较、鉴别,那个东西是什么!要登记一系列的消息并不是一件简单的事情,大家可能首先想到用数组登记对象。但如果用数组,我们要定义多大的数组才好呢,大了浪费空间,小了更加不行。所以我们要用另一种数据结构——链表。因为链表理论上可大可小,可以无限扩展。链表是一种常用的数据结构,简单地说,它是在一个对象里面保存了指向下一个同类型对象的指针。我们大体可以这样设计我们的类:struct CRuntimeClass{ ……类的名称等一切信息…… CRuntimeClass * m_pNextClass;//指向链表中下一CRuntimeClass对象的指针};链表还应该有一个表头和一个表尾,这样我们在查链表中各对象元素的信息的时候才知道从哪里查起,到哪儿结束。我们还要注明本身是由哪能个类派生。所以我们的链表类要这样设计:struct CRuntimeClass{ ……类的名称等一切信息…… CRuntimeClass * m_pBaseClass;//指向所属的基类。 CRuntimeClass * m_pNextClass;//定义表尾的时候只要定义此指针为空就可以 了。 static CRuntimeClass* pFirstClass;//这里表头指针属于静态变量,因为我们知道static变量在内存中只初始化一次,就可以为各对象所用!保证了各对象只有一个表头。};有了CRuntimeClass结构后,我们就可以定义链表了:static CRuntimeClass classCObject={NULL,NULL};//这里定义了一个CRuntimeClass对象,因为classCObject无基类,所以m_pBaseClass为NULL。因为目前只有一个元素(即目前没有下一元素),所以m_pNextClass为NULL(表尾)。至于pFirstClass(表头),大家可能有点想不通,它到什么地方去了。因为我们这里并不想把classCObject作为链表表头,我们还要在前面插入很多的CRuntimeClass对象,并且因为pFirstClass为static指针,即是说它不是属于某个对象,所以我们在用它之前要先初始化:CRuntimeClass* CRuntimeClass::pFirstClass=NULL;现在我们可以在前面插入一个CRuntimeClass对象,插入之前我得重要申明一下:如果单纯为了运行时类型识别,我们未必用到m_pNextClass指针(更多是在运行时创建时用),我们关心的是类本身和它的基类。这样,查找一个对象是否属于一个类时,主要关心的是类本身及它的基类,CRuntimeClass classCCmdTarget={ &classCObject, NULL};CRuntimeClass classCWnd={ &classCCmdTarget ,NULL };CRuntimeClass classCView={ &classCWnd , NULL };好了,上面只是仅仅为一个指针m_pBaseClass赋值(MFC中真正CRuntimeClass有多个成员变量和方法),就连接成了链表。假设我们现在已全部构造完成自己需要的CRuntimeClass对象,那么,这时候应该定义表头。即要用pFirstClass指针指向我们最后构造的CRuntimeClass对象——classCView。CRuntimeClass::pFirstClass=&classCView;现在链表有了,表头表尾都完善了,问题又出现了,我们应该怎样访问每一个CRuntimeClass对象?要判断一个对象属于某类,我们要从表头开始,一直向表尾查找到表尾,然后才能比较得出结果吗。肯定不是这样!大家可以这样想一下,我们构造这个链表的目的,就是构造完之后,能够按主观地拿一个CRuntimeClass对象和链表中的元素作比较,看看其中一个对象中否属于你指定的类。这样,我们需要有一个函数,一个能返回自身类型名的函数GetRuntimeClass()。上面简单地说一下链表的过程,但单纯有这个链表是没有任何意义。回到MFC中来,我们要实现的是在每个需要有RTTI能力的类中构造一个CRuntimeClass对象,比较一个类是否属于某个对象的时候,实际上只是比较CRuntimeClass对象。如何在各个类之中插入CRuntimeClass对象,并且指定CRuntimeClass对象的内容及CRuntimeClass对象的链接,这里起码有十行的代码才能完成。在每个需要有RTTI能力的类设计中都要重复那十多行代码是一件乏味的事情,也容易出错,所以MFC用了两个宏代替这些工作,即DECLARE_DYNAMIC(类名)和IMPLEMENT_DYNAMIC(类名,基类名)。从这两个宏我们可以看出在MFC名类中的CRuntimeClass对象构造连接只有类名及基类名的不同!到此,可能会有朋友问:为什么要用两个宏,用一个宏不可以代换CRuntimeClass对象构造连接吗?个人认为肯定可以,因为宏只是文字代换的游戏而已。但我们在编程之中,头文件与源文件是分开的,我们要在头文件头声明变量及方法,在源文件里实具体实现。即是说我们要在头文件中声明:public:static CRuntimeClass classXXX //XXX为类名virtual CRuntime* GetRuntimeClass() const;然后在源文件里实现:CRuntimeClass* XXX::classXXX={……};CRuntime* GetRuntimeClass() const;{ return &XXX:: classXXX;}//这里不能直接返回&classXXX,因为static变量是类拥有而不是对象拥有。我们一眼可以看出MFC中的DECLARE_DYNAMIC(类名)宏应该这样定义:#define DECLARE_DYNAMIC(class_name) public: static CRuntimeClass class##class_name; virtual CRuntimeClass*… Continue reading MFC关键技术(2)
MFC六大关键技术(1)
我并不认为MFC减轻了程序员们的负担,MFC出现的目的虽然似乎是为了让程序员不用懂得太多就可以进行视窗编程,但本人在MFC里徘徊了很久很久(因为那时没有书本详细介绍MFC的原理),毫无收获。可能朋友们会说,怎么一定要了解MFC的具体呢,“黑箱”作业不行吗?这不是微软的初衷吗?不行!!!如果这样,我宁愿永远不选择MFC!在学电脑之前,本人学习的东西大都与艺术不无关系,小学时参加过全国书画比赛获银奖。儿时的爱好就是在一张纸上随心所欲地画画!MFC“黑箱”就象一幅硕大的抽象画(抽象到你不能理解),它用铅笔勾画好线条,然后请你填颜色。我们怎么能忍受“黑箱”作业?我们选择C++,就是因为它够自由,够艺术,我们可以在此放飞幻想。所以,我们要攻克MFC。伟大孙老师在剖析MFC的时候虽然尽心尽力,但可能由于篇幅所限,说得并不大清楚(我相信许多学员都有这方面的感受)。在此,我突发奇想,想与大家一同分享一下著名的MFC六大关键技术。从什么地方开始讲起好呢?我觉得回到最初摸索MFC的时候,从基本谈起最好。因为我知道,一个走过来程序员,总是忘记了当初自己是怎么走过来的,忘记了一个学员最想知道的是什么。一个小小的问题(一两句话就可以解释的),足学以令手无寸铁的学员头大半个月,所以,我努力回忆当初是怎么让自己豁然开朗的。转入正题:MFC的六大关键技术包括:MFC程序的初始化过程。运行时类型识别(RTTI)。动态创建。永久保存。消息映射。消息传递。MFC程序的初始化过程1、设计一个简单完整MFC程序,产生一个窗口。当然这不能让AppWizard自动为我们生成。我们可以在Win32 Application工程下面那样写:#include <afxwin.h>class MyApp : public CWinApp{public: BOOL InitInstance() //②程序入点 { CFrameWnd *Frame=new CFrameWnd();//构造框架 m_pMainWnd=Frame; //将m_pMainWnd设定为Frame; Frame->Create(NULL,”最简单的窗口”);//建立框架 Frame->ShowWindow(SW_SHOW); //显示框架 return true; //返回 }};MyApp theApp; //①建立应用程序。 设定链接MFC库,运行,即可看见一个窗口。 从上面,大家可以看到建立一个MFC窗口很容易,只用两步:一是从CWinApp派生一个应用程序类(这里是MyApp),,然后建立应用程序对象(theApp),就可以产生一个自己需要的窗口(即需要什么样就在InitInstance()里创建就行了)。整个程序,就改写一个InitInstance()函数,创建那么一个对象(theApp),就是一个完整的窗口程序。这就是“黑箱”作业的魅力!!!!在我们正想为微软鼓掌的时候,我们突然觉得心里空荡荡的,我们想知道微软帮我们做了什么事情,而我们想编自己的程序时又需要做什么事情,那怕在上面几行的程序里面,我们还有不清楚的地方,比如,干嘛有一个m_pMainWnd指针变量,它从哪里来,又要到哪里去呢?想一想在DOS下编程是多么美妙的一件事呵,我们需要什么变量,就声明什么变量,需要什么样的函数,就编写什么样的函数,或者引用函数库……但是现在我们怎么办!!!我们可以逆向思维一下,MFC要达到这种效果,它是怎么做的呢?首先我们要弄明白,VC不是一种语言,它就象我们学c语言的时候的一个类似记事本的编辑器(请原谅我的不贴切的比喻),所以,在VC里面我们用的是C++语言编程,C++才是根本(初学者总是以为VC是一门什么新的什么语言,一门比C++先进很多的复杂语言,汗)。说了那么多,我想用一句简单的话概括“MFC‘黑箱’就是帮助我们插入了‘C++代码’的东西”。既然MFC黑箱帮我们插入了代码,那么大家想想它会帮我们插入什么样的代码呢?他会帮我们插入求解一元二次方程的代码吗?当然不会,所以它插入的实际上是每次编写窗口程序必须的,通用的代码。再往下想,什么才是通用的呢?我们每次视窗编程都要写WinMain()函数,都要有注册窗口,产生窗口,消息循环,回调函数……即然每次都要的东西,就让它们从我们眼前消失,让MFC帮忙写入!要知道MFC初始化过程,大家当然可以跟踪执行程序。孙老师的第三课跟踪了很长一段时间,我相信大家都有点晕头转向。本人觉得那怕你理解了MFC代码,也很容易让人找不着北,我们完全不懂的时候,在成千上万行程序的迷宫中如何能找到出口?我们要换一种方法,不如就来重新编写个MFC库吧,哗!大家不要笑,小心你的大牙,我不是疯子(虽然疯子也说自己不疯)。我们要写的就是最简单的MFC类库,就是把MFC宏观上的,理论上的东西写出来。我们要用最简化的代码,简化到刚好能运行。既然,我们这一节写的是MFC程序的初始化过程,上面我们还有了一个可执行的MFC程序。程序中只是用了两个MFC类,一个是CWinApp,另一个是CFrameWnd。当然,还有很多同样重要MFC类如视图类,文档类等等。但在上面的程序可以不用到,所以暂时省去了它(总之是为了简单)。好,现在开始写MFC类库吧……唉,面前又有一个大难题,就是让大家背一下MFC层次结构图。天,那张鱼网怎么记得住,但既然我们要理解他,总得知道它是从那里派生出来的吧。考虑到大家都很辛苦,那我们看一下上面两个类的父子关系(箭头代表派生):CObject->CCmdTarget->CWinThread->CWinApp->自己的重写了InitInstance()的应用程序类。CObject(同上)->CCmdTarget(同上)->CWnd->CFrameWnd 看到层次关系图之后,终于可以开始写MFC类库了。按照上面层次结构,我们可以写以下六个类(为了直观,省去了构造函数和析构函数)。/////////////////////////////////////////////////////////class CObiect{};//MFC类的基类。class CCmdTarget : public CObject{};————————————————class CWinThread : public CCmdTarget{};class CWinApp : public CWinThread{};————————————————class CWnd : public CCmdTarget{};class CFrameWnd : public CWnd{};/////////////////////////////////////////////////////////大家再想一下,在上面的类里面,应该有什么?大家马上会想到,CWinApp类或者它的基类CCmdTarget里面应该有一个虚函数virtual BOOL InitInstance(),是的,因为那里是程序的入口点,初始化程序的地方,那自然少不了的。可能有些朋友会说,反正InitInstance()在派生类中一定要重载,我不在CCmdTarget或CWinApp类里定义,留待CWinApp的派生类去增加这个函数可不可以。扯到这个问题可能有点越说越远,但我想信C++的朋友对虚函数应该是没有太多的问题的。总的来说,作为程序员如果清楚知道基类的某个函数要被派生类用到,那定义为虚函数要方便很多。也有很多朋友问,C++为什么不自动把基类的所有函数定义为虚函数呢,这样可以省了很多麻烦,这样所有函数都遵照派生类有定义的函数就调用派生类的,没定义的就调用基类的,不用写virtual的麻烦多好!其实,很多面向对象的语言都这样做了。但定义一个虚函数要生成一个虚函数表,要占用系统空间,虚函数越多,表就越大,有时得不偿失!这里哆嗦几句,是因为往后要说明的消息映射中大家更加会体验到这一点,好了,就此打往。上面我们自己解决了一个问题,就是在CCmdTarge写一个virtual BOOL InitInstance()。大家再下想,我们还要我们MFC“隐藏”更多的东西:WinMain()函数,设计窗口类,窗口注册,消息循环,回调函数……我们马上想到封装想封装他们。大家似乎隐约地感觉到封装WinMain()不容易, 觉得WinMain()是一个特殊的函数,许多时候它代表了一个程序的起始和终结。所以在以前写程序的时候,我们写程序习惯从WinMain()的左大括写起,到右大括弧返回、结束程序。我们换一个角度去想,有什么东西可以拿到WinMain()外面去做,许多初学者们,总觉得WinMain()函数天大的函数,什么函数都好象要在它里面才能真正运行。其实这样了解很片面,甚至错误。我们可以写一个这样的C++程序:////////////////////////////////////////////////////#include <iostream.h>class test{public: test(){cout<<“请改变你对main()函数的看法!”<<endl;}};test test1;/**************************/void main(){}////////////////////////////////////////////////////在上面的程序里,入口的main()函数表面上什么也不做,但程序执行了(注:实际入口函数做了一些我们可以不了解的事情),并输出了一句话(注:全局对象比main()首先运行)。现在大家可以知道我们的WinMain()函数可以什么都不做,程序依然可以运行,但没有这个入口函数程序会报错。那么WinMain()函数会放哪个类上面呢,请看下面程序:#include… Continue reading MFC六大关键技术(1)