本文搜集汇总VC的5则小技巧,非常实用,对于VC程序设计有很好的参考借鉴价值,详情如下:
1.如何获取程序所在的路径
也就是获取你这个程序本身所在的路径。
在应用程序类CxxApp的头文件中定义一个变量CString m_exePath;用来放置程序的路径名,在应用程序类CxxApp的InitInstance()函数中加入如下语句:
1
2
3
4
5
6
7
8
9
10
11
|
TCHAR m_Path[MAX_PATH]; GetModuleFileName( NULL, m_Path, MAX_PATH ); //获取程序路径(包括程序名) int i = 0, j; while ( m_Path[i]!=0 ) { if ( m_Path[i]=='\' ) j = i; i++; } m_Path[j+1] = '' ; m_exePath.Format( "%s" , m_Path ); //分离路径名(去掉程序名) |
这段程序执行后,字符串变量m_exePath中放置的就是程序所在路径,其中不包括程序名。
获取程序的位置有什么用呢?
(1)打开与应用程序在一起放置的数据文件:
如果你运行程序过程中使用过打开文件对话框打开过其它路径下的文件,这时系统的默认路径就发生了改变,有可能使你原定的数据文件打不开了,如果采用以下方法就可以没问题了:
1
2
|
CFile file; file.Open( m_exePath+ "数据文件名" , CFile::modeRead ); |
(2)放置程序运行中的临时文件:
同样,当系统的默认路径发生改变后,程序中生成的临时文件就会放得到处都是,成了一个个垃圾文件,采用以下方法可使临时文件只放在程序所在路径下:
1
2
3
|
CFile file; file.Open( m_exePath+ "临时文件名" , CFile::modeCreate | CFile::modeWrite ); …… |
程序结束时,用下面的方法删除临时文件:
1
|
CFile::Remove( m_exePath+ "临时文件名" ); |
2.如何在你的程序中执行其它程序
在自己的程序中调用其它程序的方法有好几种,这里我介绍我用过的两种:
(1)WinExec()函数:
一般用法:
1
|
WinExec(m_PathName,SW_SHOWNORMAL); |
m_PathName为执行程序的路径名,必须为可执行文件。
如:
1
|
WinExec( "C:\Program Files\Internet Explorer\iexplore.exe" ,SW_SHOWNORMAL); //为打开IE浏览器 |
(2)ShellExecute()函数:
一般用法:
1
|
ShellExecute(NULL,NULL,m_PathName,NULL,_T( "c:\temp" ),SW_SHOWNORMAL); |
m_PathName为打开的程序路径名;
_T("c:\temp")为工作目录;
与WinExec()不同的是ShellExecute()函数也可以打开非可执行文件,比如你指定的文件为.txt,结果会打开记事本装入该文件。我用这种方法调用自己制作的帮助文件(.chm)效果很好。
3.如果不使用串行化,如何在程序结束时保存文件?
在文档-视图结构中,用串行化自动保存文件在各种VC书上都有介绍。现在的问题是我不使用串行化,而是自己动手保存,当点击窗口的关闭按钮时,如何提示并保存文档。
用ClassWizard在文档类(CxxDoc)中添加函数CanCloseFrame(),再在其中加入保存文件的语句就可以了。
例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
//退出程序 BOOL CEditDoc::CanCloseFrame(CFrameWnd* pFrame) { CFile file; if (b_Flag) //b_Flag为文档修改标志,在修改文档时将其置为True { int t; t=::MessageBox(NULL, "文字已经改变,要存盘吗?" , "警告" , MB_YESNOCANCEL | MB_ICONWARNING); //弹出提示对话框 if (t==0 || t==IDCANCEL) return false ; if (t==IDYES) { CString sFilter= "Text File(*.txt)|*.txt||" ; CFileDialog m_Dlg(FALSE, "txt" ,NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,( LPCTSTR )sFilter,NULL); //定制文件对话框 int k=m_Dlg.DoModal(); //弹出文件对话框 if (k==IDCANCEL || k==0) return false ; m_PathName=m_Dlg.GetPathName(); //获取选择的文件路径名 file.Open(m_PathName,CFile::modeCreate | CFile::modeWrite); file.Write(m_Text,m_TextLen); //数据写入文件 file.Close(); } } return CDocument::CanCloseFrame(pFrame); } |
这样当你单击窗口上的关闭按钮时,如果数据已修改了,就会弹出一个提示保存数据的对话框,提示你保存数据。
程序中的b_Flag是数据修改标志,应该在修改数据时进行设置,m_Text是准备保存的数据,放在文档内。
4.POSITION怎么用?
POSITION类型数据用于表征各种列表中元素的位置,它类似于数组的下标,但又有所不同。主要区别是:
我们不能访问POSITION型数据的值,也不能对POSITION数据型数据进行加减、比较等运算。
用POSITION型数据访问列表时,都是采用迭代法,一般格式为:
1
2
3
4
5
6
|
POSITION pos; //定义pos型变量 pos = GetHeadPosition(); //获取列表起始元素位置 while ( pos ) { x = GetNext(pos); //获取pos处的列表值,同时修改pos为下一个元素位置 } |
GetNext()就是一种迭代,其格式为:
1
|
TYPE GetNext(POSITION& rPosition); |
首先,它返回当前pos位置处的元素;再就是把pos值修改为下一个元素位置。这样循环时,可依次取得列表中各元素的值;当到达列表尾时,pos为NULL,循环结束。
所以使用POSITION型数据时,你不要试图用加减等操作去修改它,只能用GetNext()(向后迭代)或GetPrev()(向前迭代)反复迭代来修改它的值。
如果你想直接到达指定值,还可以用Find()函数或FindIndex()函数获得指定值的POSITION值。
1
2
|
POSITION Find(TYPE Value); //用于在列表中查找值为Value的元素的POSITION值; POSITION FindIndex( int nIndex); //用于获取列表中第nIndex个元素的POSITION值,nIndex从0开始。 |
如:
1
2
|
pos = FindIndex(5); //求列表中第5个元素的位置 x = GetNext(pos); //读取元素的值 |
总之,POSITION类型在多种涉及列表的类中提供,不同的类提供的函数有所不同,但用法都是类似的。
5.如何从完整的文件路径中分离文件名和路径名?
从路径中分离文件名:
1
2
3
4
5
6
7
8
9
|
CString GetFileName(CString pathname) { for ( int i=pathname.GetLength()-1; i>=0; i-- ) { if ( pathname[i]=='\' ) break ; } return pathname.Mid( i+1 ); } |
从路径中分离路径名(去除文件名):
1
2
3
4
5
6
7
8
9
10
11
|
CString GetPath(CString pathname) { int i = 0, j; while ( i<pathname.GetLength() ) { if ( pathname[i]=='\' ) j = i; i++; } return pathname.Left( j+1 ); } |