printf("%s",szLogicalDriveStrings+iSub);
}
printf("\n");
return0;
}
四、MFCclass和Genericclass和FormClass使用详细区别
MFCclass:
建立基于MFC的类,比如视图,frame,控件等等,从MFC类库派生,可以在Baseclass中选择父类。
Genericclass:
geniricclass就是自己写的类,普通C++类,没有派生始祖,包含头文件后,可以使用任何MFC类。
使用genericclass,它不选择MFC中的类作为基类,也就是没有基类,或者你手工在Baseclass中填上父类。
输入任何类做基类
genericclass,是一个一般的类,可以不从mfc的类中继承,也可以从mfc的类中继承,但自己一定要注意亲自加入mfc的头文件,同时不会有消息映射表,这些都要手动添加。
FormClass:
应该是指MFC中带界面资源模板的类,一般都需要选择模板ID,包括CFormView,CRecordView,CDAORecordView和CDialog四种类
但是VC会根据实际项目的类型是dialog,SDI,MDI来选择classvizard里面下拉框中的可选类。
基于dialog的项目,添加formclass时只显示CDialog,前三种不显示(它认为,那三个view类在对话框中不必要使用)基于SDI或MDI的项目,添加formclass时下拉框显示上述4种类。
FormClass是窗口类,一般情况下用这项时,VC会同时为你生成相应的窗口MFCClass表示从MFC类库派生,可以在Baseclass中选择父类。
FormClass表示从CDialog派生的类,可以在DialogID中选择对话框资源ID。
GenericClass表示从其它类型的类派生,可以在Baseclass中填上父类
_int64是个什么类型?
父类和基类是一个意思!
五、类的删除方法?
一般在文件视图中把那个类的h和cpp文件删掉,别忘了你的还有资源里的dialog资源,则可以选中该资源,然后用delete键删除。
再看看类视图中还有没有。
如果还有,到工程所在的目录,把*.clw和*.ncb*.opt文件还有你的那个类的文件删掉,再进到工程里检查。
六、一个最基本的单文档视图的MFC程序,包含CxxApp、CxxDoc、CMainFrame、CxxView和CAboutDlg五个类。
它们在程序开始运行时被创建的顺序是:
CxxApp、CxxDoc、CMainFrame、CxxView、CAboutDlg。
C**App()定义了窗体加载之前需要做的预处理。
比如一个加密的软件,打开后提示用户输入密码。
这个事件的处理程序就要写在C**App()的InitInstance(中。
CMainFrame()包含了对工具栏、状态栏、窗口的定义。
C**View包含了最主要的处理功能,如菜单操作、快捷键、用户交互操作等。
CAboutDlg定义了ABOUT对话框。
其中,前四个都是在程序主窗口出现之前被创建的,CAboutDlg是在“关于”对话框弹出时被创建的
1CAboutDlg//这个是关于对话框里面是构造和析构2CMainFrame//主框架`是在窗口生成之前准备工作全在这吗?
3CTestApp//这个是什么`initlnstance()在这里也是初始化什么对象?
4CTestDoc//这是文档`是管理哪些文档`对初学者来说很少用呐?
5CTestView视图`这个常用OnDraw我了解一些`我想知道`是不是默认就调用一次?
还有个问题啊`我想加个音乐`虽然加成功了`但是`我一直不明白加在哪个函数里`运行就有音乐?
看过孙鑫的教程后来忘了`各位高手各抒已见,互相学习
需要系统地学习一下。
CTestApp是基于WinApp的,WinApp封装了程序的主入口WinMain,WinMain就和c语言的main函数地位一样,是Win32程序的入口。
在MFC的封装中,一个程序启动,Windows调用WinMain,这个WinMain函数现在由MFC事先写好藏好了,你不能也不需要修改,在这个预定义的WinMain里面会调用CWinApp的InitInstrance函数。
你仔细看你CTestApp:
:
InitInstrance函数,在这里一个CMainFrame的对象被创建,文档模板被创建,主窗口通过ShowWindow(SW_SHOW)被显示出来。
CMainFrame是个框架,是你整个应用程序的主窗口,他负责管理应用程序的菜单,工具栏,状态栏等。
中间的区域,成为客户区,由View类来管理,View类也是一个窗口,他是MainFrame的子窗口。
OnDraw函数负责绘制客户区的内容,该函数会被多次调用,他可以被你自己调用,比如你调用View类的UpdateWindow,或者在Document类中调用UpdateAllViews等等,MFC自动会调用OnDraw。
他还会被Windows调用,Windows在需要刷新窗口的时候发送给窗口WM_PAINT消息,MFC事先已经预定义了,在响应WM_PAINT消息的时候会调用OnDraw。
何时Windows会发送WM_PAINT呢,比如窗口从最小化还原,比如窗口被用户改变了大小等等。
这部分内容最好看看WindowsGDI,WindowsGDI是Windows操作系统整个可视化界面的基础。
然后你最后一个问题,何时才能被播放音乐。
你仔细想想就容易得到答案了,整个程序从App类的InitInstrance开始,在InitInstranc
学过PE文件格式,你就明白,程序在进入WinMain之前要做很多事情,比如初始Dos头,分配函数表,初始化全局变量。
之后才进入程序入口(WinMain)
MFC对WindowsAPI进行了封装。
在用向导编译成的二进时代码,MFC编译器链接器把源文件编译成PE文件格式存储在磁盘上。
程序执行的时候,从PE文件头开始执行,在进入Winmain函数之前,进行一系列的必备的初始化。
MFC对这一系列的过程进行了封装。
提供给编程人员的第一个裸露程序入口就是CWinApp的InitInstance(),其实程序的入口依然是WinMain()函数。
大家都知道,每个程序都有拥有一个进程,每个进程至少有一个线程就是主线程。
CWinThread类是MFC用来封装线程的,这个主线程就是在WinMain函数中创建的,包括UI线程和工作者线程。
因此每个MFC程序至少使用一个CWinThread派生类。
被MFC程序员熟知的CWinApp应用类就从这里派生。
InitInstance是CWinThread的一个虚函数,InitInstance就是“初始化实例”的意思,可见,它是在实例创建时首先被调用的。
应用程序总要重载这个虚函数,进行系统设置,创建运行环境。
例如,主窗口一定要在InitInstance()中创建,因为该函数退出后就进入该线程的消息循环。
MFC执行流程。
_tWinMain(WinMain的别名,用define替换的)-》AfxWinMain->初始化线程,调用InitInstance初始化窗口,调用Run函数进入消息循环。
七、MFC中dodataexchange的作用:
将界面上的控件与一个变量或者一个类对象相关联!
数据交换。
例如文本框控件当关联了一个变量的时候就需要在这个控件和这个变量之间通过DoDataExchange建立联系;然后通过调用UpdateData选择当用户更改了输入的时候是否更新变量值或更改程序变量值后是否更新界面
操作注意问题:
.
1.调用UpdateData选择当用户更改了输入的时候是否更新变量值
2.当在按钮中,引入另一个类时,必须在未设置按钮函数时候,就已经创建好将要引入的类,否则会造成无法读取要引入的类,!
!
!
八、GetBuffer()主要作用是将字符串的缓冲区长度锁定,releaseBuffer则是解除锁定,使得CString对象在以后的代码中继续可以实现长度自适应增长的功能。
CString:
:
GetBuffer有两个重载版本:
LPTSTRGetBuffer();LPTSTRGetBuffer(intnMinBufferLength);
在第二个版本中,当设定的长度小于原字符串长度时,nMinBufLength=nOldLen,该参数会被忽略,不分配内存,指向原CString;
当设定的长度大于原字符串本身的长度时就要重新分配(reallocate)一块比较大的空间出来。
而调用第一个版本时,应如通过传入0来调用第二个版本一样。
是否需要在GetBufer后面调用ReleaseBuffer(),是根据你的后面的程序是否需要继续使用该字符串变量,并且是否动态改变其长度而定的。
如果你GetBuffer以后程序自函数就退出,局部变量都不存在了,调用不调用ReleaseBuffer没什么意义了。
这是一个非常容易被用错的函数,主要可能是由于大家对它的功能不太了解。
其实点破的话,也不是那么深奥。
GetBuffer(intsize)是用来返回一个你所指定大小可写内存的成员方法。
它和被重载的操作符LPCTSTR还是有点本质区别的,LPCTSTR是直接返回一个只读内存的指针,而GetBuffer则是返回一个可以供调用者写入的内存,并且,你可以给定大小。
下面是个简单的,但也是非常典型的例子:
intreadFile(CString&str,constCString&strPathName)
{
FILE*fp=fopen(strPathName,"r");//打开文件
fseek(fp,0,SEEK_END);
intnLen=ftell(fp);//获得文件长度
fseek(fp,0,SEEK_SET);//重置读指针
char*psz=str.GetBuffer(nLen);
fread(psz,sizeof(char),nLen,fp);//读文件内容
str.ReleaseBuffer();//千万不能缺少
fclose(fp);
}
上面的函数是GetBuffer函数最典型的用法了,其实它就相当于申请一块nLen大小的内存,只不过,这块内存是被引用在CString对象的内部而已,这是非常有效的一种用法,如果不直接用GetBuffer函数来申请的话,那么你必须用new操作符(或者malloc()函数)在CString的外部申请,然后再将申请的内存拷贝到CString对象中,显然这是一个非常冗余的操作,会使你函数的效率大大下降。
ReleaseBuffer函数是用来告诉CString对象,你的GetBuffer所引用的内存已经使用完毕,现在必须对它进行封口,否则CString将不会知道它现在所包含的字符串的长度,所以在使用完GetBuffer之后,必须立即调用ReleaseBuffer函数重置CString的内部属性,其实也就是头部信息。
补充一下:
GetBuffer说白了就两个功能:
1:
就是将CString里面的内存交到外部一个来处理,外部可以直接修改它的内容。
2:
重新修改CString的内存大小,这个数值不包含null结尾符。
另一个典型的用法:
就是将CString里面的内容变为int或long型,需要先获取里面的内存指针。
这样就可以先GetBuffer(内存大小)方便直接转换。
如果在外部修改了CString里面的内容,在重新使用CString之前,需调用ReleaseBuffer()也就是说,ReleaseBuffer不需要每次都调用。
CString:
:
ReleaseBuffer只是一个形象的说法,完全是跟GetBuffer对应而起的名字。
我觉得如果函数名改为UpdateBuffer的就不会出现这种误解 先来看一段代码:
CStrings="hello"; LPTSTRps=s.GetBuffer();
strcpy(ps,"hi"); s.ReleaseBuffer();
此时调用s.GetLength()获取的值是2,正确无误。
但如果注释掉s.ReleaseBuffer()这一行,s.GetLength()获取的值则是5,哈哈,错了。
怎么会这样呢,我们来看看MFC中ReleaseBuffer的代码:
voidReleaseBuffer(intnNewLength=-1)
{
if(nNewLength==-1)
{
nNewLength=StringLength(m_pszData);
}
SetLength(nNewLength);
} 很明显ReleaseBuffer只有一个作用,就是更新字符串的长度。
CString内,GetLength获取字符串长度并不是动态计算的,而是在赋值操作后计算并保存在一个int变量内的,当通过GetBuffer直接修改CString时,那个int变量并不可能自动更新,于是便有了ReleaseBuffer。
其实,计算长度还能用strlen(),这个就算不ReleaseBuffer也不会出错,但如果不ReleaseBuffer,在+=这种赋值时字符串很可能会跟想要得到的不同。
九、给类添加函数与添加消息相应有何区别?
消息相应的添加和类函数的添加方式有何不同?
什么时候用消息相应?
何种情况下采用类函数?
如:
OnCancel()函数的添加和WM_TIMER消息相应的添加
十、resource.h中的宏定义都用作什么?
例如:
#defineIDM_ABOUTBOX0x0010
#defineIDD_ABOUTBOX100
#defineIDS_ABOUTBOX101
#defineIDD_OUTPUTGIF_DIALOG102
#defineIDR_MAINFRAME128
#defineIDC_FILENAME1000
#defineIDC_BROWSE1001
//Nextdefaultvaluesfornewobjects
#ifdefAPSTUDIO_INVOKED
#ifndefAPSTUDIO_READONLY_SYMBOLS
#define_APS_NEXT_RESOURCE_VALUE129
#define_APS_NEXT_COMMAND_VALUE32771
#define_APS_NEXT_CONTROL_VALUE1002
#define_APS_NEXT_SYMED_VALUE101
#endif
#endif
注意:
IDC_BROWSE类似的标识是用户自己设定的各个控件的ID号,这些ID号系统会自动赋给相应的数字值以便在程序运行过程中用于实现相应的控件的操作。
在学习过程中,必须保证例程中控件的ID号等标识符与自己所建立的控件的标识符一致才能进行对比分析,负责往往分析不出结果,特别使用beyondcompare软件进行对比分析时,这一点也是自己常常出错的地方。
当然,还有一部分是系统自行设定的ID号,如:
#defineIDOK1这些是在系统\VC98\Include\WINUSER.H。
在Include文件夹中存放这系统自带的许多头文件,其中定义了众多常用的系统标识符。
#defineIDOK1
#defineIDCANCEL2
#defineIDABORT3
#defineIDRETRY4
#defineIDIGNORE5
#defineIDYES6
#defineIDNO7
#if(WINVER>=0x0400)
#defineIDCLOSE8
#defineIDHELP9
十一、对话框构造函数中为什么初始化部分的程序为什么是灰色标识?
十二、下列是程序中给出的一些提示信息。
//NotethatLoadIcondoesnotrequireasubsequentDestroyIconinWin32
//NOTE:
theClassWizardwilladdDDXandDDVcallshere
//NOTE:
theClassWizardwilladddatamembershere
//TODO:
Addextrainitializationhere
十三、控件的ID号与联系控件的变量之间的关系?
CStaticm_ImageDemo;这些与控件关联的变量的类型怎么理解?
CEditm_WaterText;
CEditm_FileName;
UINTm_OriginX;
UINTm_OriginY;
十四、为什么要将
//#ifdef_DEBUG
//#definenewDEBUG_NEW
//#undefTHIS_FILE
//staticcharTHIS_FILE[]=__FILE__;
//#endif
注释起来,而不注释时结果显示new错误?
十五、怎么建立一个新的对话框类?
在模型树中建立一个对话框类,但没有和对话框资源连接起来。
如何连接?
分别建立对话框类和对话框资源,在选中对话框资源利用类向导建立两者之间的联系;另一种方法是先建立对话框资源,在利用对话框资源类向导建立新对话框类,并同时建立两者之间的联系。
十六、通常建立的程序缺少对话框类是由于其对话框资源设置不合理所导致,通过检查对话框资源的个属性,可以解决这个问题。
十七、complie和bulid功能有什么区别?
十八、对调试中各种变量及数据的变化并没有深刻的理解。
例如this指针、消息、地址等。
。
可以查找一些相关的详细介绍书籍。
十九、怎么理解数据在内存中的存放形式?
如:
地址内存上存储的数据值
0012FE98296B(低位)D600(高位)060000其中自左向右:
按照167+166+165+164+163+162+161+160=00D66B29
其中:
32位计算机其内存地址用了8位十六进制数据表示,该地址上存放的数据也是用8位二进制数据表示(自左向右8位数据,多余的数据位无效!
)
若是32位计算机则表示:
该内存存放的数据为32