大名鼎鼎?a target="_blank" style="color: rgb(0, 68, 170); text-decoration: none; ">Zend公司在IT界的知名度是一路飙升啊Q她是php的商业公司,随着php在编E语a中越来越多的被用,据本Z灵通的消息Q自9月以来,php已经越C++排名W三?/a>Q这真是一个振奋h心的消息Q当初选择做phpQ此时此刻,也让我感到gQ尽如此,你不得不承认Qphp能拿到第三名的好成WQ一定是有我的A(ch)献的~!!那么有没有一天,php能做到编E语a中的头把交椅呢?我想不会(x)的,如果你在哪里看到q个排行榜,那它一定是不权威的?/p> OKQ言归正传,Z很多同学认ؓ(f)zend studio是官方网站的不正认知(主要表现是向我索取zend server,zend Guard的注册码Q,我就来说说这个zend公司她到底是个什么东西,或许我把标题Ҏ(gu)?span style="text-decoration: underline; ">zend公司的那些事?/span>》,大概更能W合中国人的阅读?fn)惯。顺便说一下,zend studio是公益性民间站?/strong>?/p> ׃zend公司的品和php有着l对的关p,然而其每个产品之间竟然也有q千丝万~的联系Q这是一个很值得U道的事情了Q甚臛_金庸的武侠小说有异曲同工之妙。下面我们一一i叨Q排名不分先后,但zend studio排第一个)?span id="more-833"> 1、Zend Stduio q是我认为zend公司唯一q有必要存在的真正原因,我厌烦了媒体一提到zend studioq本宣U的道比“一个屡获大奖的专业 PHP 集成开发环境,具备功能强大的专业编辑工具和调试工具……”Q虽然事实上实是这么回事,zend studio实是一个强大的php集成开发环境,我选择Q我喜欢Q但q里我想提醒下大Ӟzend studio是商业Y件?/p> 2、Zend Debugger L介绍一个商业公司的商业产品Q难免有打商业广告之嫌,虽然我根本就不是一个商人,所以接下来我就马上搬出zend debuggerQ我前不久刚好写了一?a style="color: rgb(0, 68, 170); text-decoration: none; ">zend debugger的终极安装教E?/a>Q,zend debugger是zend公司为数不多的免费品,体积不大Q安装方便,功能也很强大Q一般需要调试phpE序的时候,装上它就够用了?/p> 3、Zend Server 实际上我q没有搞清楚zend server的真正意图,据说针对php做了专门的优化,q且是商业YӞ但其不全是收费的Q只是部分组Ӟ我大U在3个月前试用过zend serverQ记忆有些模p)Q内|的是apache服务器(当然你可以不选择内置Q,虽然奚w成了Zend Optimizer、Zend Guard Loader、Zend Data Cache、Zend Debugger、Zend FrameworkQ但在我看来q和免费?a style="color: rgb(0, 68, 170); text-decoration: none; ">xampp
4、Zend Optimizer
q又是zend 公司的免费品之一QZend Optimizer的最大作用是解密解析被zend Guard加密了的php源文Ӟ兼顾优化php性能的作用,因此Q?zhn)在部|服务器的时候将zend OptimizerZ安装上没有Q何的坏处Q当Ӟ如果你购C一份Zend Guard加密q的php源码Q那你就必须安装她了?/p>
5、Zend Guard
Zend Guard是一个非常有用的产品Q当然她也是一个商业YӞ如果你不打算你的php代码开源,那么可以选择Zend Guard来保护你的研I成果,最新版的宝?p,据说强度不是一般的大,能够在保护期内安全不被破解。值得一提的是,用Zend Guard加密q了的php源代码,在你的服务器环境中必d装Zend Optimizer?#8220;正常q行”之(看!金庸的大师风范就彰显出来?/em>Q?/p> 6、Zend Framework q又是zend 公司q年来的重要产品Qphp界Framework的兴P无疑的简化开发,提高效率Q即“敏捷高效”四字斚wQ这个仅仅是E序员在开发工作上的描qͼ而php的运行效率性能上却q有质的飞跃。因此,本h也不是非常崇框Ӟ管国内的qeephp,thinkphp{著名框架发展的如火如荼Q框架的q捧者也是如潮水一般,有个Z然我行我素的“坐以待毙”Q他是——gently。然而Zend Frameworkq一无是处,Ҏ(gu)一个伟大的框架产品Q发展稳健,现在的用L(fng)也是蛮庞大的Q中国h比较q信官方Q当然也因ؓ(f)她确实不错)?strong>Zend studio从宝?pd始,已经完美的支持zend Framework的开发、调试运行一条龙了?/p> 7、Zend Core 直译q来?em>zend核心
8、Zend Platform
更准的说她是一整套的企业服务器解决Ҏ(gu)Q企业应用从来都是和大型联pd一L(fng)Q因此,什么集啊、阵列啊、控制中心啊、等{等{对zend platform来说全都不在话下Q她能够跟踪Phpq行中的错误Q监控phpq行的性能Q精的扑և瓉Q这是多么牛逼的产品啊。那么,需要多钱呢?只要998Q全球限?0套,赶紧拿v?sh)话订购吧?#8230;…抽风了一下,依我看,zend server正要逐步替代掉zend platformQ不止是做嫁衣,zend q要生新娘Q因此,Zend Server风头正劲。Zend Platform与zend studio的关pd是前者能够提供给后者非常强大的服务端支持,当然q个强大是zend debugger无法企及(qing)的,当大多数时候,我们个h开发者用不着q么强大Q官方可以下载到Zend Platform?0天试用版Q就是说Ҏ(gu)商业软gQ,抱歉Q我也没有Zend Platform的注册码或者注册机。她与zend server的关pdQ就是Zend Server在嫁衣里面包了个新娘?/p>
Zend公司是一个有潜力的公司,与各界的合作正纷U展开Q也zend走远?/p>
用Visual C++操作INI文g
在我们写的程序当?L一些配|信息需要保存下?以便完成E序的功?最单的办法是这些信息写入INI文g?E序初始化时再读?具体应用如下:
一.信息写?INI文g?
1.所用的WINAPI函数原型?
BOOL WritePrivateProfileString(
LPCTSTR lpAppName,
LPCTSTR lpKeyName,
LPCTSTR lpString,
LPCTSTR lpFileName
);
其中各参数的意义:
LPCTSTR lpAppName 是INI文g中的一个字D名.
LPCTSTR lpKeyName 是lpAppName下的一个键?通俗讲就是变量名.
LPCTSTR lpString 是键?也就是变量的?不过必须为LPCTSTR型或CString型的.
LPCTSTR lpFileName 是完整的INI文g?
2.具体使用Ҏ(gu):讄有一名学?需把他的姓名和q龄写入 c:\stud\student.ini 文g?
CString strName,strTemp;
int nAge;
strName="张三";
nAge=12;
::WritePrivateProfileString("StudentInfo","Name",strName,"c:\\stud\\student.ini");
此时c:\stud\student.ini文g中的内容如下:
[StudentInfo]
Name=张三
3.要将学生的年龄保存下?只需整型的值变为字W型卛_:
strTemp.Format("%d",nAge);
::WritePrivateProfileString("StudentInfo","Age",strTemp,"c:\\stud\\student.ini");
?信息从INI文g中读入程序中的变?
1.所用的WINAPI函数原型?
DWORD GetPrivateProfileString(
LPCTSTR lpAppName,
LPCTSTR lpKeyName,
LPCTSTR lpDefault,
LPTSTR lpReturnedString,
DWORD nSize,
LPCTSTR lpFileName
);
其中各参数的意义:
前二个参C WritePrivateProfileString中的意义一?
lpDefault : 如果INI文g中没有前两个参数指定的字D名或键?则将此Dl变?
lpReturnedString : 接收INI文g中的值的CString对象,即目的缓存器.
nSize : 目的~存器的大小.
lpFileName : 是完整的INI文g?
2.具体使用Ҏ(gu):现要上一步中写入的学生的信息dE序?
CString strStudName;
int nStudAge;
GetPrivateProfileString("StudentInfo","Name","默认姓名",strStudName.GetBuffer(MAX_PATH),MAX_PATH,"c:\\stud\\student.ini");
执行?strStudName 的gؓ(f):"张三",若前两个参数有误,其gؓ(f):"默认姓名".
3.d整型D用另一个WINAPI函数:
UINT GetPrivateProfileInt(
LPCTSTR lpAppName,
LPCTSTR lpKeyName,
INT nDefault,
LPCTSTR lpFileName
);
q里的参数意义与上相?使用Ҏ(gu)如下:
nStudAge=GetPrivateProfileInt("StudentInfo","Age",10,"c:\\stud\\student.ini");
?循环写入多个?讄有一E序,要将最q用的几个文g名保存下?具体E序如下:
1.写入:
CString strTemp,strTempA;
int i;
int nCount=6;
file://共有6个文件名需要保?br style="line-height: 23px; ">for(i=0;i<nCount;i++)
{
strTemp.Format("%d",i);
strTempA=文g?
//文g名可以从数组,列表框等处取?
::WritePrivateProfileString("UseFileName","FileName"+strTemp,strTempA,"c:\\usefile\\usefile.ini");
}
strTemp.Format("%d",nCount);
::WritePrivateProfileString("FileCount","Count",strTemp,"c:\\usefile\\usefile.ini");
//文件L写入,以便d.
2.d:
nCount=::GetPrivateProfileInt("FileCount","Count",0,"c:\\usefile\\usefile.ini");
for(i=0;i<nCount;i++)
{
strTemp.Format("%d",i);
strTemp="FileName"+strTemp;
::GetPrivateProfileString("CurrentIni",strTemp,"default.fil", strTempA.GetBuffer(MAX_PATH),MAX_PATH,"c:\\usefile\\usefile.ini");
//使用strTempA中的内容.
}
补充四点:
1.INI文g的\径必d?文g名前面的各目录必须存在,否则写入不成?该函数返?FALSE ?
2.文g名的路径中必Mؓ(f) \\ ,因ؓ(f)在VC++? \\ 才表CZ?\ .
3.也可INI文g攑֜E序所在目?此时 lpFileName 参数? ".\\student.ini".
//----------------------------------------------------------------------------------
/*
cdQCIni
版本Qv2.0
加入高操作的功?br style="line-height: 23px; ">v1.0
梦小孩于2003q某?br style="line-height: 23px; ">一般操作完?/p>
cLqͼ(x)
本类可以?ini文gq行操作
*/
文g 1:
#pragma once
#include "afxTempl.h"
class CIni
{
private:
CString m_strFileName;
public:
CIni(CString strFileName):m_strFileName(strFileName)
{
}
public:
//一般性操作:(x)
BOOL SetFileName(LPCTSTR lpFileName); //讄文g?br style="line-height: 23px; ">CString GetFileName(void); //获得文g?br style="line-height: 23px; ">BOOL SetValue(LPCTSTR lpSection, LPCTSTR lpKey, LPCTSTR lpValue,bool bCreate=true); //讄键|bCreate是指D名?qing)键名未存在Ӟ是否创徏?br style="line-height: 23px; ">CString GetValue(LPCTSTR lpSection, LPCTSTR lpKey); //得到键?
BOOL DelSection(LPCTSTR strSection); //删除D名
BOOL DelKey(LPCTSTR lpSection, LPCTSTR lpKey); //删除键名
public:
//高操作Q?br style="line-height: 23px; ">int GetSections(CStringArray& arrSection); //枚D出全部的D名
int GetKeyValues(CStringArray& arrKey,CStringArray& arrValue,LPCTSTR lpSection); //枚DZD内的全部键名及(qing)?/p>
BOOL DelAllSections();
};
文g 2:
#include "StdAfx.h"
#include "ini.h"
#define MAX_ALLSECTIONS 2048 //全部的段?br style="line-height: 23px; ">#define MAX_SECTION 260 //一个段名长?br style="line-height: 23px; ">#define MAX_ALLKEYS 6000 //全部的键?br style="line-height: 23px; ">#define MAX_KEY 260 //一个键名长?/p>
BOOL CIni::SetFileName(LPCTSTR lpFileName)
{
CFile file;
CFileStatus status;
if(!file.GetStatus(lpFileName,status))
return TRUE;
m_strFileName=lpFileName;
return FALSE;
}
CString CIni::GetFileName(void)
{
return m_strFileName;
}
BOOL CIni::SetValue(LPCTSTR lpSection, LPCTSTR lpKey, LPCTSTR lpValue,bool bCreate)
{
TCHAR lpTemp[MAX_PATH] ={0};
//以下if语句表示如果讄bCreate为falseӞ当没有这个键名时则返回TRUEQ表C出错)
//!*&*none-value*&!* q是个垃圑֭W没有特别意义,q样乱写是防止凑巧相同?br style="line-height: 23px; ">if (!bCreate)
{
GetPrivateProfileString(lpSection,lpKey,"!*&*none-value*&!*",lpTemp,MAX_PATH,m_strFileName);
if(strcmp(lpTemp,"!*&*none-value*&!*")==0)
return TRUE;
}
if(WritePrivateProfileString(lpSection,lpKey,lpValue,m_strFileName))
return FALSE;
else
return GetLastError();
}
CString CIni::GetValue(LPCTSTR lpSection, LPCTSTR lpKey)
{
DWORD dValue;
TCHAR lpValue[MAX_PATH] ={0};
dValue=GetPrivateProfileString(lpSection,lpKey,"",lpValue,MAX_PATH,m_strFileName);
return lpValue;
}
BOOL CIni::DelSection(LPCTSTR lpSection)
{
if(WritePrivateProfileString(lpSection,NULL,NULL,m_strFileName))
return FALSE;
else
return GetLastError();
}
BOOL CIni::DelKey(LPCTSTR lpSection, LPCTSTR lpKey)
{
if(WritePrivateProfileString(lpSection,lpKey,NULL,m_strFileName))
return FALSE;
else
return GetLastError();
}
int CIni::GetSections(CStringArray& arrSection)
{
/*
本函数基Q?br style="line-height: 23px; ">GetPrivateProfileSectionNames - ?ini 文g中获?Section 的名U?br style="line-height: 23px; ">如果 ini 中有两个 Section: [sec1] ?[sec2]Q则q回的是 'sec1',0,'sec2',0,0 Q当你不知道
ini 中有哪些 section 的时候可以用q个 api 来获取名U?nbsp;
*/
int i;
int iPos=0;
int iMaxCount;
TCHAR chSectionNames[MAX_ALLSECTIONS]={0}; //ȝ提出来的字符?br style="line-height: 23px; ">TCHAR chSection[MAX_SECTION]={0}; //存放一个段名?br style="line-height: 23px; ">GetPrivateProfileSectionNames(chSectionNames,MAX_ALLSECTIONS,m_strFileName);
//以下循环Q截断到两个q箋?
for(i=0;i<MAX_ALLSECTIONS;i++)
{
if (chSectionNames[i]==0)
if (chSectionNames[i]==chSectionNames[i+1])
break;
}
iMaxCount=i+1; //要多一?号元素。即扑և全部字符串的l束部分?br style="line-height: 23px; ">arrSection.RemoveAll();//清空原数l?/p>
for(i=0;i<iMaxCount;i++)
{
chSection[iPos++]=chSectionNames[i];
if(chSectionNames[i]==0)
{
arrSection.Add(chSection);
memset(chSection,0,MAX_SECTION);
iPos=0;
}
}
return (int)arrSection.GetSize();
}
int CIni::GetKeyValues(CStringArray& arrKey,CStringArray& arrValue, LPCTSTR lpSection)
{
/*
本函数基Q?br style="line-height: 23px; ">GetPrivateProfileSection- ?ini 文g中获得一个Section的全部键名及(qing)值名
如果ini中有一个段Q其下有 "D?=?" "D?=?"Q则q回的是 'D?=?',0,'D?=?',0,0 Q当你不知道
获得一个段中的所有键?qing)值可以用q个?nbsp;
*/
int i;
int iPos=0;
CString strKeyValue;
int iMaxCount;
TCHAR chKeyNames[MAX_ALLKEYS]={0}; //ȝ提出来的字符?br style="line-height: 23px; ">TCHAR chKey[MAX_KEY]={0}; //提出来的一个键?/p>
GetPrivateProfileSection(lpSection,chKeyNames,MAX_ALLKEYS,m_strFileName);
for(i=0;i<MAX_ALLKEYS;i++)
{
if (chKeyNames[i]==0)
if (chKeyNames[i]==chKeyNames[i+1])
break;
}
iMaxCount=i+1; //要多一?号元素。即扑և全部字符串的l束部分?br style="line-height: 23px; ">arrKey.RemoveAll();//清空原数l?br style="line-height: 23px; ">arrValue.RemoveAll();
for(i=0;i<iMaxCount;i++)
{
chKey[iPos++]=chKeyNames[i];
if(chKeyNames[i]==0)
{
strKeyValue=chKey;
arrKey.Add(strKeyValue.Left(strKeyValue.Find("=")));
arrValue.Add(strKeyValue.Mid(strKeyValue.Find("=")+1));
memset(chKey,0,MAX_KEY);
iPos=0;
}
}
return (int)arrKey.GetSize();
}
BOOL CIni::DelAllSections()
{
int nSection;
CStringArray arrSection;
nSection=GetSections(arrSection);
for(int i=0;i<nSection;i++)
{
if(DelSection(arrSection[i]))
return GetLastError();
}
return FALSE;
}
使用Ҏ(gu)Q?br style="line-height: 23px; ">CIni ini("c:\\a.ini");
int n;
/*获得?br style="line-height: 23px; ">TRACE("%s",ini.GetValue("D?","?"));
*/
/*d?br style="line-height: 23px; ">ini.SetValue("自定义段","?","?);
ini.SetValue("自定义段2","?","?,false);
*/
/*枚D全部D名
CStringArray arrSection;
n=ini.GetSections(arrSection);
for(int i=0;i<n;i++)
TRACE("%s\n",arrSection[i]);
*/
/*枚D全部键名?qing)?br style="line-height: 23px; ">CStringArray arrKey,arrValue;
n=ini.GetKeyValues(arrKey,arrValue,"D?");
for(int i=0;i<n;i++)
TRACE("键:(x)%s\n|(x)%s\n",arrKey[i],arrValue[i]);
*/
/*删除键?br style="line-height: 23px; ">ini.DelKey("D?","?");
*/
/*删除D?br style="line-height: 23px; ">ini.DelSection("D?");
*/
/*删除全部
ini.DelAllSections();
*/
操作配置文gini
1.基础知识
INI文gQInitialization file Q又UCؓ(f)初始化文Ӟ是用来保存应用程序设|和选项的一U特D的ASCII文gQ以“.ini”作ؓ(f)文g扩展名,也被U做配置文g或概要文ӞProfileQ。除了各个应用程序可以拥有自q有的初始化文件外QW(xu)indowspȝq提供有一个系l的初始化文件Win.iniQƈ由此对当前的Windowspȝq行配置Q同时也可以在其内记录系l内其他应用E序在运行时的选项?/p>
通常为应用程序所U有的初始化文g比较?yu),q样可以减少E序在初始化时所d的信息量Q从而提高程序的启动速度。而系l初始化文gWin.ini׃除了记录有关pȝ的大量信息外Q还存储着许多其他应用软g的初始化数据Q因此其通常比较庞大Q访问的数据量要q比U有的配|文件大得多。如没有必要Q一般不对Win.ini文gq行操作Q但如果待存取的信息涉及(qing)到Windowspȝ环境或是其他应用E序? 必dWin.iniq行d讉KQƈ在访问的同时发送WM_WININICHANGE消息l所有的层H口Q通知其他q程pȝ初始化文件已被更攏V?/p>
配置文g里的信息之所以能为系l和众多不同cd的应用程序读取ƈ识别Q是׃其内部对数据的存取采用了预先U定?#8220;?值对QEntry-value pairsQ?#8221;存储l构, q对待存取的数据分门别类地进行存储。下面是pȝ目录下Win.ini文g的部分内容:(x)
[windows]
load=
run=
NullPort=None
[Desktop]
WallpaperStyle=2
Pattern=(?
在此Q配|文件将信息分ؓ(f)若干“?#8221;Q节标题攑֜Ҏ(gu)号中Q如“[Desktop]”是Desktop节,在每一个节中包含了一些与之相关的“?#8221;Qƈ通过{号对其q行赋倹{一般Ş式如下:(x)
[SECTION]
ENTRY=VALUE
在初始化文g中,VALUE值只能有两种数据cdQ数值和字符丌ӀWindows分别两种数据cd提供了两套API函数对初始化文gq行数据dQ在写入初始化文件时则只支持对字W串的写入,数值等cd必须先进行数据类型的转换Q然后才能写入到初始化文件。私有初始化文g的访问 对私有初始化文g的数据存取是由GetPrivateProfileIntQ)、GetPrivateProfileStringQ)和W(xu)ritePrivateProfileStringQ){三个API函数来完成的。其函数说明如下Q?/p>
UINT GetPrivateProfileInt(LPCTSTR lpAppName, // 节名地址
LPCTSTR lpKeyName, // 名地址
INT nDefault, // 在项名没有找到时q回的缺省?br style="line-height: 23px; "> LPCTSTR lpFileName // 初始化文件名地址
);
DWORD GetPrivateProfileString(LPCTSTR lpAppName, // 节名地址
LPCTSTR lpKeyName, // 名地址
LPCTSTR lpDefault, // ~省字符?br style="line-height: 23px; "> LPTSTR lpReturnedString, // 存放字符串的~冲区地址
DWORD nSize, // ~冲区大?br style="line-height: 23px; "> LPCTSTR lpFileName // 初始化文件名地址
);
BOOL WritePrivateProfileString(LPCTSTR lpAppName, // 节名地址
LPCTSTR lpKeyName, // 名地址
LPCTSTR lpString, // 要写入的字符串地址
LPCTSTR lpFileName // 初始化文件名地址
);
其中QGetPrivateProfileIntQ)q回的是初始化文件lpFileName中lpAppName节内lpKeyName的整数|如果没有扑ֈ该项则返回缺省值nDefault。如果此目存在Q但g为整敎ͼ则返?。如果某目的g含有非数字字W则只返回第一个非数字前的字符Q例如对?#8220;Value = 21century”则只q回数?1。初始化文g名lpFileName可以是全路径也可以只是文件名Q如果不指定具体路径QW(xu)indowspȝ在pȝ目录Ҏ(gu)件进行寻找。GetPrivateProfileStringQ)和W(xu)ritePrivateProfileStringQ)的用法基本与之类|只是处理对象的数据类型不同?/p>
2 知识应用
U有初始化文件主要用来保存同应用E序当前状态相关的一些信息,当程序退出后Q这些信息由于已写入到初始化文g而得以保留,当程序再ơ运行时Q可以通过Ҏ(gu)初始化文件各Ҏ(gu)据的d而得知此应用E序在上ơ运行期间的相关信息。下面这D代码即通过对私有初始化文g的访问而对E序的运行次数和上一ơ的q行日期q行记录Q?/p>
CString sPath,sMsg,sTime,sDate;
char buffer[255];
// 获取当前应用E序全\?br style="line-height: 23px; ">GetModuleFileName(NULL, buffer, MAX_PATH);
sPath = CString(buffer);
sPath = sPath.Left(sPath.ReverseFind('\\'));
// 得到初始化文件的全\?br style="line-height: 23px; ">sPath += "\\Sample04.ini";
// 得到E序累计q行ơ数
UINT Time = GetPrivateProfileInt("PROGRAM", "RUNTIME", 0, sPath);
// 得到上次q行日期
GetPrivateProfileString("DATE", "LAST", "2002-11-1", buffer, 1000, sPath);
// 昄从初始化文g获取到的文g信息
sMsg.Format("本Y件共q行q?d?上次q行日期?s", Time, CString(buffer));
AfxMessageBox(sMsg);
// 累加q行ơ数,q保存到初始化文?br style="line-height: 23px; ">Time++;
sTime.Format("%d", Time);
WritePrivateProfileString("PROGRAM", "RUNTIME", sTime, sPath);
// 获取当前日期,q保存到初始化文?br style="line-height: 23px; ">CTime tm = CTime::GetCurrentTime();
sDate.Format("%d-%d-%d", tm.GetYear(), tm.GetMonth(), tm.GetDay());
WritePrivateProfileString("DATE", "LAST", sDate, sPath);
在程序执行后Q初始化文gSample04.ini的内容ؓ(f)Q?br style="line-height: 23px; ">[DATE]
LAST =2002-11-12
[PROGRAM]
RUNTIME =1
pȝ目录下的Win.ini是一U特D的初始化文Ӟ主要为系l提供初始化服务Q在pȝ启动时将被系l所讉KQƈҎ(gu)其所保存的参数值对pȝq行配置。Windows专门提供了三个API函数GetProfileIntQ)、GetProfileStringQ)和W(xu)riteProfileStringQ)对Win.iniq行d讉KQ其函数用法同访问私有初始化文g的那几个函数非常cMQ只是不必再L定初始化文g名。下面是q三个函数的原型声明Q?/p>
UINT GetProfileInt(LPCTSTR lpAppName, // 节名地址
LPCTSTR lpKeyName, // 名地址
INT nDefault // 在项名没有找到时q回的缺省?br style="line-height: 23px; ">);
DWORD GetProfileString(LPCTSTR lpAppName, // 节名地址
LPCTSTR lpKeyName, // 名地址
LPCTSTR lpDefault, // ~省字符串地址
LPTSTR lpReturnedString, // 存放字符串的~存的地址
DWORD nSize // ~存的大?br style="line-height: 23px; ">);
BOOL WriteProfileString(LPCTSTR lpAppName, // 节名地址
LPCTSTR lpKeyName, // 名地址
LPCTSTR lpString // 要写入字W串的地址
);
只要对前面对U有初始化文件进行访问的代码E加改动卛_程序的配置信息d到Win.ini中,改动后的代码如下Q?/p>
CString sPath,sMsg,sTime,sDate;
// 得到E序累计q行ơ数
UINT Time = GetProfileInt("PROGRAM", "RUNTIME", 0);
// 得到上次q行日期
GetProfileString("DATE", "LAST", "2002-11-1", buffer, 1000);
// 昄从初始化文g获取到的文g信息
sMsg.Format("本Y件共q行q?d?上次q行日期?s", Time, CString(buffer));
AfxMessageBox(sMsg);
// 累加q行ơ数,q保存到初始化文?br style="line-height: 23px; ">Time++;
sTime.Format("%d", Time);
WriteProfileString("PROGRAM", "RUNTIME", sTime);
// 获取当前日期,q保存到初始化文?br style="line-height: 23px; ">CTime tm = CTime::GetCurrentTime();
sDate.Format("%d-%d-%d", tm.GetYear(), tm.GetMonth(), tm.GetDay());
WriteProfileString("DATE", "LAST", sDate);
׃Win.ini文g是系l初始化文gQ在E序没有q行前文件内不含“DATE”?#8220;PROGRAM”{自定义的节以及(qing)其下各项Q因此在E序W一ơ执行后Q将由WriteProfileStringQ)函数向Win.ini文g末尾创徏相关节、项Qƈ完成数据的写入?br style="line-height: 23px; ">
@class 声明一个类 @fn 声明一个函?/div> @brief 要说?/div> /** @file RenderMgr.h @brief 渲染理c?br style="line-height: normal; ">@date 3/16/2006 @author lethean */ @param 声明一个参?/div> @note 注解 @par paragraphQ自定义一个段落标题,cMhtml?lt;p> @code 代码CZQ需要用@endcode闭Q代码段中不需要加前置*?/div> /** @brief dbmp文g @remarks 试一?br style="line-height: normal; ">@param [in] dc 传入一个dc用于临时操作 @param [in] filename bmp文g?br style="line-height: normal; ">@note 屏幕dc只能在一处被使用Q请保传入屏幕dc后其他地方不?x)操作该dc @par 代码CZ: @code //使用 CDC* dc = AfxGetMainWindow()->GetDC(); Bitmap bmp( dc , "test.bmp"); AfxGetMainWindow()->ReleaseDC( dc ); @endcode */ 对于单行的前|注释可以用///Q或?** blahblah */ 样式 ///我是一个变?/div> int index; 对于单行的后|注释,需要加一?<"W号 int count; ///< 我也?/div> /** 协议标识 */ enum ProtoId { PROTOID_LOGIN, /**< 登陆协议*/ PROTOID_BROWSE, /**< 览协议*/ }; @defgroup是用来定义新模块?/div> 集中在某个头文g中定义所有的模块Q然后在属于q个模块的类定义处用@ingroup EnginePrerequisite.h?/div> /** @defgroup Render Render渲染模块 @defgroup Resource Resource理模块 @defgroup Sound Sound声音模块 @defgroup Anim Anim动画模块 @defgroup Math Math数学库模?br style="line-height: normal; ">@defgroup Script Script脚本模块 */ RenderMgr.h?/div> /** @class RenderMgr @ingroup Render */ JavaDoccdQ?/span> /** * ... E序注释 ... */ QtcdQ?/span> /*! * ... E序注释... */ 单行型式Q?/span> /// q是一个简z型的注?/span> //! q也是一个简z型的注?/span> ?/span>Doxygen的这几种基本注释cd可以徏立以徏立文档了Q如果需要更多复杂功能,Doxygenq可以提供高U格式如l(groupQ和列表?/span> Doxygen的常用注释参敎ͼ(x)
Doxygen的用,如下Q?/span> E:\>xstring目录包含下列文gQ?/span> Xstring.cpp Xstring.h 其中xstring.h里对xstringcȝStrToIntҎ(gu)的注释如下:(x) /** * 0. 序言 Doxygen是基于GPL的开源项目,是一个非怼U的文档系l,当前支持在大多数unixQ包括linuxQ,windows家族QMacpȝ上运行,完全支持C++, C, Java, IDLQCorba和Microsoft 家族Q语aQ部分支持PHP和C#语言Q输出格式包括HTML、latex、RTF、ps、PDF、压~的HTML和unix manpage。有很多开源项目(包括前两文章介l的log4cpp和CppUnitQ都使用了doxygen文档pȝ。而国内的开发h员却使用的不多,q里从开发h员用的角度介绍q个工具Q开发h员用最的代h(hun)快掌握q种技术,q结合这个工h讨如何撰写注释的问题。以下以linux下的C++语言Zq行介绍Q以下讨论基于doxygen1.3.3?/p> 1. doxygen使用步骤 Doxygen在生成文档时可以定义目属性以?qing)文档生成过E中的很多选项Q用下面命令能够生一个缺省的配置文gQ?br style="line-height: normal; ">doxygen -g [配置文g名] 让doxygen自动产生文档Q^常的注释风格可不行,需要遵循doxygen自己的格式。具体如何写doxygen认识的注释在W?节详l介l?/p> OKQ代码编完了Q注释也按照格式写好了,最后的文档是如何的哪?非常单,q行下面的命令,相应的文档就?x)生在指定的目录中?br style="line-height: normal; "> doxygen [配置文g名] 需要注意的是doxygenq不处理所有的注释Qdoxygen重点x与程序结构有关的注释Q比如:(x)文g、类、结构、函数、变量、宏{注释,而忽略函数内变量、代码等的注释?/p> 2. doxygen配置文g 对doxygen的配|文件的修改分ؓ(f)两类Q一U就是输出选项Q控制如何解释源代码、如何输出;一U就是项目相关的信息Q比如项目名U、源代码目录、输出文档目录等。对于第一U设|好后,通常所有项目可以共用一份配|,而后一U是每个目必须讄的。下面选择重要的,有可能需要修改的选项q行解释说明Q其他选项在配|文仉有详l解释?/p> TAG ~省?含义 3. doxygen注释 注释和代码完全分,攑֜其他地方也是允许的,但需要用特D的命o(h)加上名称或者声明进行标识,比如Qclass、struct、union、enum、fn、var、def、file、namespace、package、interfaceQ这些也是doxygenx的注释类型)。这里不推荐使用Q徏议注释尽量放在代码前后。具体用方式参见doxygen手册?/p> 3.2 doxygen常用注释格式 对函数的注释Q是比较常常需要注释的部分。除了定义其要说明以?qing)详l注释,q可以用param命o(h)对其各个参数q行注释Q用return命o(h)对返回D行注释。常见的格式如下Q?br style="line-height: normal; ">/** q行设计Ӟ通常有模块的概念Q一个模块可能有多个cL者函数组成,完成某个特定功能的代码的集合。如何对q个概念q行注释Qdoxygen提供了group的概念,生成的模块的注释?x)单独放在一个模块的面中。用下面的格式定义一个group?br style="line-height: normal; ">/** [group_name] [brief group description ] 对于某几个功能类似的代码(比如cR函数、变量){,如果希望一h加注释,而又不想提升到模块的概念Q可以通过下面的方式:(x) 3.3 doxygen常用注释命o(h) 到此为止Q常用的doxygen的注释格式讨论完毕,我们能够按照一定的格式撰写doxygen认识的注释,q能够用doxygen方便快捷的生成对应的文档Q不q注释中应该写些什么,如何撰写有效的注释可能是困扰开发h员的一个更深层ơ的问题?/p> 4. 注释的书?br style="line-height: normal; ">注释应该怎么写,写多q是写少。过多的注释甚至?x)干扰对代码的阅诅R写注释的一个ȝ原则是注释应该量用来表明作者的意图Q至也应该是对一部分代码的ȝQ而不应该是对代码的重复或者解释。对代码的重复或者解释的代码Q看代码可能更容易理解。反映作者意囄注释解释代码的目的,从解决问题的层次上进行注释,而代码ȝ性注释则是从问题的解{的层次上进行注释?/p> 推荐的写注释的过E是首先使用注释勑Z码的主要框架Q然后根据注释撰写相应的代码。对各种主要的数据结构、输出的函数、多个函数公用的变量q行详细地注释。对代码中控制结构,单一目的的语句集q行注释。下面是一些写注释旉要注意的要点Q?br style="line-height: normal; "> 避免对单独语句进行注释; 虽然使用各种IDE或者Source Insight 可以方便地在windows下阅d分析C/C++代码Q但是一步步Go to Definetion 实在令h痛苦。Doxygen能够生成函数调用关系图,所有的函数调用关系可以一目了Ӟ另外他还能统计文档中所有的c,成员变量Q成员函数等。ȝ来说QDoxygen不但能从局部把握代码,q能从全局审视代码Q后者是一般IDE和Source Insight 不能做到的。所以,使用doxygen阅读分析代码可以辑ֈ事半功倍的效果?/p> doxygen的安装很单,到官方网站下载doxygen的windows安装E序卛_。除了安装doxygen外,q需要安装graphvizQ因为doxygen需要用graphviz的dot.exe生成调用图。graphviz在它的官方网站上也可以下载到安装E序。不q我下蝲的安装程序在安装时老是报cab文g错误。最后我下蝲了graphviz的release文gQ即安装E序下面的zip压羃文gQ下载完成后解压~即可?/p> 安装完doxygen后即可进行适当的配|,然后q行doxyfile生成文档。基本的配置前h早有说明Q不再赘q。需要注意的是:(x) 1.要勾选Dot选项卡下面的HAVE_DOT、CALL_GRAPH 、CALLER_GRAPH 选项。ƈ在DOT_PATH下面填入dot.exe的\径,也就是graphviz安装目录下的bin文g夏V?/p> 2.NWizard->Project选项卡下面的Scan recursivelyQ?/p> 3.NBuild选项卡下面的EXTRACT_ALL、EXTRACT_PRIVATE、EXTRACT_STATIC、EXTRACT_LOCAL_CLASSES、EXTRACT_LOCAL_METHODS选项 4.如果E序里面有中文,Project选项卡下的DOXYFILE_ENCODING和Input选项卡下面的INPUT_ENCODING改ؓ(f)GBK 5.可以勾掉LATEX输出Q这栯省编译时?/p> 5. 参考资?br style="line-height: normal; ">1. doxygen homepage 2. doxygen manual 3. Code Complete: A Practical Handbook of Software Construction. Redmond, Wa.: Microsoft Press, 880 pages, 1993. ISBN: 1-55615-484-4. 6. 使用doxygen |
代码写多了难免需要做文档Q给自己q是l别人看都需要如此,q次XBOX360制作Q前期没怎么写注释,回头改Bug都要猜半天自己写的代码是什么意思。更别提别h写的东西Q?00行代码也没有一句注释,q好不是我维护,否则要疯掉了?/p>
׃一天功夫尝试了一下Doxygen的用,q好不难Q但是有些磕绊l,它自q文档也说不清楚,|上搜出来的教程也只是给出样子,遇到的问题还是靠自己试了几十次才搞定?/p>
不管如何Q常用的东西都可以弄出来了。脓(chung)在下面:(x)
-----------------------------------------------------------------------------------
1.所有注释都可以使用///开?C++风格)?br>
2.cM前必d?//描述Q否则会(x)产生警告【Compound cd is not documented?br> 描述中最好不要带有此cȝcdQ否则会(x)产生两个链接(但指向同一个文?影响观?br>
3.public和protected?x)自动生成,但是private要在Expert的Build选项里勾中EXTRACT_PRIVATEQstatic成员也是如此?br>
4.函数注释方式
/// Constructor【函数描q?br> /// @param [in] pos The position of Camera in world coordinate 【参数描q??br> /// @param [in] lookat The point Camera looks at in world coordinate 【参数描q??br> BaseCamera( const D3DXVECTOR3& pos, const D3DXVECTOR3& lookat );
5.变量注释方式
D3DXVECTOR3 m_Position; /*!< Camera position point in world coordinate */ ?br> D3DXVECTOR3 m_Position; ///< Camera position point in world coordinate
两种方式产生的结果不同。前者会(x)单独产生一块Member Data Documentation注释Q后者会(x)在Pubilc/Protected/Private Attributes变量描述后紧跟注释?br>
6.@参数和\参数相同
7.产生描述序和注释顺序相同,一般风gؓ(f)
/// 函数描述
/// @param 参数描述
/// @return q回值描q?br> /// @retval q回? q回?描述
/// @retval q回? q回?描述
/// @remarks 注意事项
/// @note 注意事项Q功能同@remarks,昄字样不同
/// @par 自定义图块,后面可跟CZ代码之类
/// @code(必须使用@endcodel束)
/// CZ代码(无需~进)
/// @endcode
/// @see 其他参考项【生指向参考的链接?br> 函数代码声明
8.Ҏ(gu)W号
/// - 产生一个黑色圆?br>
9.定义在类体里面的enum
/// Camera types
enum CAMERA_TYPE
{
CAMERA_FIRST_VIEW,/*!< Camera that looks from the first view */
CAMERA_MODEL_VIEW,///< Camera that looks from the third view
};
两种风格相同?br>
以下开始的w是全局非类内定义,在文件最开?我尝试是在include之前) 必须加上?// \file 文g名】,否则不会(x)生成注释【没有File Memberc(din)?br>
10. 定义在文仉面的?br> #define CAMERA_TYPE_NUMBER ///< The number of camera types. ?br> #define CAMERA_TYPE_NUMBER /*!< The number of camera types. */
风格说明??br>
11. 非类内enum定义?0. 两种风格相同。见9?br>12. 非类内typedef定义?0. 风格说明??/p>