2008年1月31日星期四

Clistctrl自动下滚

pList.EnsureVisible(nRow,true);

2008年1月30日星期三

VC++ 改变Dialog窗口大小及定位,SetWindowPos()

1.引用库函数 #include "easysize.h",见:
codeproject::Easysize

2.函数SetWindowPos
原型为BOOL SetWindowPos(const CWnd * pWndInsertAfter,int x,int y,int cx,int cy,UINT nFlags);
pWndInsertAfter为指向标识窗口类型的CWnd对象的指针。
x,y为窗口左上角的坐标。
cx,cy为窗口的宽与高。
nFlags确定窗口的大小及位置。当为SWP_NOSIZE时,忽略cx,cy。当为SWP_NOMOVE时,忽略x,y。


3.代码:
BEGIN_EASYSIZE_MAP(CUnpackConfirm)
EASYSIZE(IDOK,ES_KEEPSIZE,ES_KEEPSIZE,ES_BORDER,ES_BORDER,0)
EASYSIZE(IDCANCEL,ES_KEEPSIZE,ES_KEEPSIZE,ES_BORDER,ES_BORDER,0)
EASYSIZE(IDC_STATIC_TEXT,IDC_STATIC_TITLE,ES_BORDER,ES_BORDER,ES_BORDER,0)

END_EASYSIZE_MAP

BOOL CUnpackConfirm::OnInitDialog()
{

CDialog::OnInitDialog();


// * set for easysize.h *
INIT_EASYSIZE;

if(!t_ColorStatic) //
t_ColorStatic.SubclassDlgItem(IDC_STATIC_TITLE,this);


if(!s_ColorStatic) //
s_ColorStatic.SubclassDlgItem(IDC_STATIC_TEXT,this);


intialTitleFont();
intialTextFont();

t_ColorStatic.SetWindowText("Sollen jetzt folgende Daten zurückgespielt werden?");

//--get CView pointer
CMDIFrameWnd *pFrame = (CMDIFrameWnd*)AfxGetApp()->m_pMainWnd;
CMDIChildWnd *pChild = (CMDIChildWnd *) pFrame->GetActiveFrame();
CUnpackView *pView = (CUnpackView *) pChild->GetActiveView();
//--

CString text (_T(""));

lHigh = 200;

switch (pView->nGroupFocus)
{
case GROUP_UNPACK:
if (pView->m_pageUnpack.m_pUnpackListCtrl.isApolloChecked)
{
text += "- Apollo.mdb.gz\n";
addHigh(); //lHigh += 10;

......

setText(text);

UpdateData(false);
Invalidate();

//MFC: CWnd::SetWindowPos
CRect Rect1;
pFrame->GetWindowRect(&Rect1); //get size and position of mainframe

//CRect Rect2;
//GetDlgItem(IDC_STATIC_TEXT)->GetWindowRect(&Rect2); // ???????
//Rect2.bottom = lHigh + Rect2.bottom;


long x, y;
x = Rect1.left + (Rect1.Width() - 420)/2;
y = Rect1.top + (Rect1.Height() - lHigh)/2;

CUnpackConfirm::SetWindowPos(NULL,
x , //left
y, //top
420, //width
lHigh, // hight.
SWP_SHOWWINDOW);


UPDATE_EASYSIZE;

UpdateData();
Invalidate();

return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE

}

CString 剖析

CString类功能强大,比STL的string类有过之无不及.新手使用CString时,都会被它强大
的功能所吸引.然而由于对它内部机制的不了解,新手在将CString向C的字符数组转换时
容易出现很多问题.因为CString已经重载了LPCTSTR运算符,所以CString类向const
char *转换时没有什么麻烦,如下所示:

char a[100];
CString str("aaaaaa");
strncpy(a,(LPCTSTR)str,sizeof(a));

或者如下:
strncpy(a,str,sizeof(a));
以上两种用法都是正确地.因为strncpy的第二个参数类型为const char *.所以编译器
会自动将CString类转换成const char *.很多人对LPCTSTR是什么东西迷惑不解,让我们
来看看:
1.LP表示长指针,在win16下有长指针(LP)和短指针(P)的区别,而在win32下是没有区别
的,都是32位.所以这里的LP和P是等价的.
2.C表示const
3.T是什么东西呢,我们知道TCHAR在采用UNICODE方式编译时是wchar_t,在普通时编译成char
那么就可以看出LPCTSTR(PCTSTR)在UINCODE时是const wchar_t *,PCWSTR,LPCWSTR,在
多字节字符模式时是const char *,PCSTR,LPCSTR.
接下来我们看在非UNICODE情况下,怎样将CString转换成char *,很多初学者都为了方便
采用如下方法:
(char *)(LPCSTR)str.这样对吗?我们首先来看一个例子:
CString str("aa");
strcpy((char *)(LPCTSTR)str,"aaaaaaaa");
cout<<(LPCTSTR)str<<endl;

在Debug下运行出现了异常,我们都知道CString类内部有自己的字符指针,指向一个已分
配的字符缓冲区.如果往里面写的字符数超出了缓冲区范围,当然会出现异常.但这个程
序在Release版本下不会出现问题.原来对CString类已经进行了优化.当需要分配的内存
小于64字节时,直接分配64字节的内存,以此类推,一般CString类字符缓冲区的大小为
64,128,256,512...这样是为了减少内存分配的次数,提高速度.
那有人就说我往里面写的字符数不超过它原来的字符数,不就不会出错了,比如
CString str("aaaaaaa");
strcpy((char *)(LPCTSTR)str,"aa");
cout<<(LPCTSTR)str<<endl;

这样看起来是没什么问题.我们再来看下面这个例子:
CString str("aaaaaaa");
strcpy((char *)(LPCTSTR)str,"aa");
cout<<(LPCTSTR)str<<endl;
cout<<str.GetLength()<<endl;

我们看到str的长度没有随之改变,继续为7而不是2.还有更严重的问题:
CString str("aaaaaaa");
CString str1 = str;
strcpy((char *)(LPCTSTR)str,"aa");
cout<<(LPCTSTR)str<<endl;
cout<<(LPCTSTR)str1<<endl;

按说我们只改变了str,str1应该没有改变呀,可是事实时他们都变成了"aa".难道str和
str1里面的字符指针指向的缓冲区是一个.我们在Effective C++里面得知,如果你的类
内部有包含指针,请为你的类写一个拷贝构造函数和赋值运算符.不要让两个对象内部的
指针指向同一区域,而应该重新分配内存.难道是微软犯了错?
原来这里还有一个"写时复制"和"引用计数"的概念.CString类的用途很广,这样有可能
在系统内部产生大量的CString临时对象.这时为了优化效率,就采用在系统软件内部广
泛使用的"写时复制"概念.即当从一个CString产生另一个CString并不复制它的字符缓
冲区内容,而只是将字符缓冲区的"引用计数"加1.当需要改写字符缓冲区内的内容时,才
分配内存,并复制内容.以后我会给出一个"写时复制"和"引用计数"的例子
我们回到主题上来,当我们需要将CString转换成char *时,我们应该怎么做呢?其时只是
麻烦一点,如下所示:
CString str("aaaaaaa");
strcpy(str.GetBuffer(10),"aa");
str.ReleaseBuffer();

当我们需要字符数组时调用GetBuffer(int n),其中n为我们需要的字符数组的长度.使
用完成后一定要马上调用ReleaseBuffer();
还有很重要的一点就是,在能使用const char *的地方,就不要使用char *

2008年1月29日星期二

VC++ 删除整个文件夹

int CPublic::removeDir(CString lpszPath)
{
lpszPath += '\0';

SHFILEOPSTRUCT FileOp;
FileOp.fFlags = FOF_NOCONFIRMATION;
FileOp.hNameMappings = NULL;
FileOp.hwnd = NULL;
FileOp.lpszProgressTitle = NULL;
FileOp.pFrom = lpszPath;
FileOp.pTo = NULL;
FileOp.wFunc = FO_DELETE;

if ( SHFileOperation( &FileOp ) == 0 )
return NOT_ERROR;
else
return DEL_TREE_ERROR;
}


意见:
CString strWorkAreaPath;
char path[MAX_PATH];
strcpy(path,"E:\\文件夹\\aa.txt");
SetCurrentDirectory(_T("C:\\"));
strWorkAreaPath = path;

strWorkAreaPath += '\0';
SHFILEOPSTRUCT fileop;
fileop.fFlags = FOF_ALLOWUNDO ;
fileop.hwnd = NULL;
fileop.pFrom = strWorkAreaPath;
fileop.pTo = NULL;
fileop.wFunc = FO_DELETE;
fileop.fAnyOperationsAborted = TRUE;
fileop.hNameMappings = NULL;
fileop.lpszProgressTitle = _T("正在删除文件");
// fileop.fFlags &= ~FOF_ALLOWUNDO;
SHFileOperation(&fileop);

这样才叫删除文件,你的代码是删除文件夹

注意:
关键在于,lpszPath 如 "d:\\aaaa\\TFG\0" 必须有个"\0",但是用 lpszPath = lpszPath + "\0"的办法加不上。

2008年1月28日星期一

VC++, CString to CTime, CTime to CString

CString to CTime:
//"20071221_094910_IF.A3P.gz"
sYear = sName.Mid(0,4);
sMonth = sName.Mid(4,2);
sDay = sName.Mid(6,2);
sHour = sName.Mid(9,2);
sMin = sName.Mid(11,2);
sSec = sName.Mid(13,2);

nYear = atoi((LPCTSTR)sYear);
nMonth = atoi((LPCTSTR)sMonth);
nDay = atoi((LPCTSTR)sDay);
nHour = atoi((LPCTSTR)sHour);
nMin = atoi((LPCTSTR)sMin);
nSec = atoi((LPCTSTR)sSec);

CTime *dynamicTime;
dynamicTime = new CTime(nYear,nMonth,nDay,nHour,nMin,nSec,0);
DateTime = *dynamicTime;
delete dynamicTime;

CTime to CString:
CString s = m_timeFrom.Format( "%Y-%m-%d %H:%M:%S" );

VC++ boost: regex应用

下载boost_1_34_1.zip,解压
安装:
  1、打开vs2005在菜单tools中选择Visual Studio 2005 Command Prompt,打开已配置好环境的命令行。
  2、进入目录boost_1_34_1\libs\regex\build,
  编译文件:nmake -f vc8.mak
  安装(将编译好的文件复制到vs2005的特定目录下):nmake -f vc8.mak install
  删除临时文件:nmake -f vc8.mak clean
  3、Tools->Options->Projects and Solutions->VC++ Directories->Include files添加boost_1_34_1路径

  初次使用提示找不到libboost_regex-vc80-mt-gd-1_34_1.lib文件,到网上搜了下解决方法为:将 libboost_regex-vc80-mt-gd-1_34.lib改名libboost_regex-vc80-mt-gd-1_34_1.lib 放到vs或工程目录下。
4.
#include <boost/regex.hpp>
using namespace boost;
...
regex expression("^([0-9]{8})_([0-9]{6})_([[:word:]]+)\.([[:word:]]+)\.gz$");
cmatch what; // a array to store the matching string
if(regex_match(sName, what, expression
{
...

2008年1月25日星期五

_access 可判断文件夹是否存在及访问权限

////////////////////////////////////////////////////////////////////
//
// * only check if the directory exists,
// * can not comfirm if a dir accessable
//
////////////////////////////////////////////////////////////////////
DWORD dwAttr = GetFileAttributes(sDir);
if(dwAttr == 0xFFFFFFFF) //Directory doesn't exists
return false;

return true;


//////////////////////////////////////////////
// * 最终解决方法:
//////////////////////////////////////////////
#include "stdafx.h"
#include "io.h"


BOOL existDir(sDir )
{
/* Check for exist */
if( (_access( sDir , 0 )) != -1 ) //"C:\\windows"
{
return true;

}
else
{
return false;

}

}

2008年1月22日星期二

VC++ 从数据文件一次读一行

[问题提出]
一数据文件一行一条记录,我用file.readstring()一次读一行,并对读取的数据做一些处理;
请问:while(文件还没到结尾)
{
file.readstring();
...

}
??文件还没到结尾如何判断?
如果,到了指定位置不读了,过一会儿再读又如何做?
[解决方法]
while()中不用另加判断条件了,因为CStdioFile::ReadString()本身就是判断标志,若没有了(文件到头)返回NULL,因此:while(file.ReadString(s)){}就可.
[程序实现]
假设你已有了名为ts.txt的文件在你的工程目录下:
{
CStdioFile file;
CString sss;
char ccc[100];
DWORD o=0;
int ol=0;
file.Open("ts.txt",CFile::modeRead);
while(file.ReadString(sss))
{
ol++;
if(ol>1)//读两次就不读了.
break;

}
o=file.GetPosition();//记录上次的结果(读到哪了)
.................
file.Seek(o,0);//接着上回读
while(file.ReadString(sss))
{
strcpy(ccc,sss);
AfxMessageBox(ccc);
}

}

我的代码:
int CDBinfoListCt::checkReport(CString sReportFile)
{
CStdioFile file;
CString str;
CString sDollar("$$$");
CString sProtocolOK("OK!");
try
{
if (file.Open(sReportFile,CFile::modeRead|CFile::shareDenyNone))
{
while(file.ReadString(str))
{
if(str.Find(sDollar) != -1 && str.Find(sProtocolOK) != -1)
{ //AfxMessageBox("no error for a3000.bat: "+ str);
return NOT_ERROR;
}
}
}
else
{
return OPEN_FILE_FAILED;
}
}
catch(CFileException *e)
{
CString str;
str.Format("reason:%d",e->m_cause);
AfxMessageBox((LPCTSTR)str); //error C2660: 'MessageBoxA' : Funktion akzeptiert keine 1 Parameter
file.Abort();
e->Delete();
}
return REPORT_ERROR;
}

VC++得到当前系统时间日期 GetSystemTime()

一、使用MFC可以用以下代码得到:
CTime time = CTime::GetCurrentTime(); ///构造CTime对象
int m_nYear = time.GetYear(); ///年
int m_nMonth = time.GetMonth(); ///月
int m_nDay = time.GetDay(); ///日
int m_nHour = time.GetHour(); ///小时
int m_nMinute = time.GetMinute(); ///分钟
int m_nSecond = time.GetSecond(); ///秒


我们还可以用CTime::Format函数将CTime对象转换为字符串对象
例如:
CString m_strTime = time.Format("%Y-%m-%d %H:%M:%S");


运行结果:m_strTime为 2001-8-1 12:11:05

二、使用GetSystemTime()这个API函数得到系统时间

SYSTEMTIME ti;
GetSystemTime(&ti);
////我们可以通过读取SYSTEMTIME结构体成员直接得到时间
typedef struct _SYSTEMTIME {
WORD wYear;
WORD wMonth;
WORD wDayOfWeek;
WORD wDay;
WORD wHour;
WORD wMinute;
WORD wSecond;
WORD wMilliseconds;

} SYSTEMTIME, *PSYSTEMTIME;


例如:ti.wMilliseconds;可以得到毫秒时间

2008年1月17日星期四

CTabCtrl控件

VC中的CTabCtrl用法与VB、Delphi的选项卡控件有很大的不同,每个属性页是用一个“窗体”(对话框)来实现,于是要为每个属性页对话框建类,还要关联、初始化……实在麻烦得多。但是CTabCtrl可重用性比ActiveX的选项卡控件好,因为一个属性页可以被多个不同的选项卡对话框调用,就像MFC中很多属性选项卡有“General”这一选项页,可以被多个控件的属性页调用,作为“通用”的,有符合现代软件工程可重用性要求。
下面发一个最简单的代码,使用CTabCtrl控件实现属性页功能,要源码的请登陆www.maoyeah.com,技术文章专栏找。
1、建立一个基于对话框的应用程序;
2、画CTabCtrl控件,类向导中关联变量名为m_tab,新建三个对话框属性设为Child,None,用ClassWizard生成新的类,基类为Cdialog,分别为Cpage0,Cpage1,Cpage2,ID号分别为 IDD_DIALOG0,IDD_DIALOG1,IDD_DIALOG2。在主对话框中加入三个变量,Cpage0 page0; Cpage1 page1;Cpage2 page2。别忘了在主对话框的头文件中要加入#include "Page0.h", #include "Page1.h",#include "Page2.h"
3、在主对话框的OnInitDialog()内初始化 :
// TODO: Add extra initialization here

//初始化m_tab控件
m_tab.InsertItem(0," 呵呵,茂叶工作室 ");
m_tab.InsertItem(1," 嘻嘻 ");
m_tab.InsertItem(2," 哈哈,www.maoyeah.com ");

//建立属性页各页
page0.Create(IDD_DIALOG0,GetDlgItem(IDC_TAB1));
page1.Create(IDD_DIALOG1,GetDlgItem(IDC_TAB1));
page2.Create(IDD_DIALOG2,GetDlgItem(IDC_TAB1));
//设置页面的位置在m_tab控件范围内
CRect rect;
m_tab.GetClientRect(&rect);
rect.top+=20;
rect.bottom-=4;
rect.left+=4;
rect.right-=4;
page0.MoveWindow(&rect);
page1.MoveWindow(&rect);
page2.MoveWindow(&rect);
page1.ShowWindow(TRUE);
m_tab.SetCurSel(1);

4、m_tab控件属性页选择时显示各页:
void CMy3Dlg::OnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult)
{
// TODO: Add your control notification handler code here
int CurSel;
CurSel=m_tab.GetCurSel();
switch(CurSel)
{
case 0:
page0.ShowWindow(TRUE);
page1.ShowWindow(FALSE);
page2.ShowWindow(FALSE);

break;
case 1:
page0.ShowWindow(FALSE);
page1.ShowWindow(TRUE);
page2.ShowWindow(FALSE);

break;
case 2:
page0.ShowWindow(FALSE);
page1.ShowWindow(FALSE);
page2.ShowWindow(TRUE);

break;
default: ;

}

*pResult = 0;

}


错误:Dialog 必须选IDD_OLE_PROPAGE_xxx, 否则插入的控件不响应鼠标事件.

2008年1月14日星期一

Corrupt apollo.mdb bings unpack.exe "Failed to create empty document. "

CDaoDatabase::Open()本身是void,当遇到.mdb结构性破坏时,无法返回错误报告。
解决方案:利用抛出异常返回结果
BOOL CPublic::openDB()
{
......
//----build connection to source Datenbase by CDaoDatabase.
// *here must check the sourceDB is the right .mdb file and kann be found
// it can be the wrong .mdb file , "test.mdb"
try
{
CDaoWorkspace daoWorkspace;
//CDaoWorkspace::CompactDatabase( _T( "C:\\DB1.MDB" ),_T( "C:\\DB2.MDB" ) );
//CDaoWorkspace::RepairDatabase( (LPCTSTR)sourceDB );
daoWorkspace.Open( (LPCTSTR)sourceDB );
if (!daoWorkspace.IsOpen())
return false;
else
daoWorkspace.Close();

}
catch( CDaoException* e )
{
//AfxMessageBox( e->m_pErrorInfo->m_strDescription );
e->Delete();
return false; //利用CDaoWorkspace::Open可避免.lpb文件的产生,造成死锁

}
//----build connection to source Datenbase by CDaoDatabase.
// *here must check the sourceDB is the right .mdb file and kann be found
// it can be the wrong .mdb file , "test.mdb"

try
{
m_DaoDatabase.Open((LPCTSTR)sourceDB,FALSE,FALSE,_T(""));

}
catch(CDaoException* e)
{
e->Delete();
return false; //important, if .mdb corrupt ist.

}
//
......
return true;

}

2008年1月11日星期五

SetFileAttributes,更改文件写保护属性

//get rid of writeprotect featcher of sourcefile.
SetFileAttributes((LPCTSTR)sourceDB,FILE_ATTRIBUTE_NORMAL);
//

2008年1月9日星期三

常用的字符串处理函数

字符串标准函数的原型在头文件string.h中。

1.输入字符串──gets()函数

(1)调用方式:gets(字符数组)

(2)函数功能:从标准输入设备(stdin)──键盘上,读取1个字符串(可以包含空格),并将其存储到字符数组中去



(3)使用说明


1)gets()读取的字符串,其长度没有限制,编程者要保证字符数组有足够大的空间,存放输入的字符串。

2)该函数输入的字符串中允许包含空格,而scanf()函数不允许。


2.输出字符串──puts()函数

(1)调用方式:puts(字符数组)

(2)函数功能:把字符数组中所存放的字符串,输出到标准输出设备中去,并用‘\n’取代字符串的结束标志‘\0’

。所以用puts()函数输出字符串时,不要求另加换行符。

( 3)使用说明

1)字符串中允许包含转义字符,输出时产生一个控制操作。

2)该函数一次只能输出一个字符串,而printf()函数也能用来输出字符串,且一次能输出多个。


3.字符串比较──strcmp()函数

(1)调用方式:strcmp(字符串1 ,字符串2)

其中“字符串”可以是串常量,也可以是1维字符数组。

(2)函数功能:比较两个字符串的大小。

如果:字符串1=字符串2,函数返回值等于0;

字符串1字符串2,函数返回值正整数。

(3)使用说明

1)如果一个字符串是另一个字符串从头开始的子串,则母串为大。

2)不能使用关系运算符“==”来比较两个字符串,只能用strcmp() 函数来处理。

[案例6.7] gets函数和strcmp函数的应用。

/*案例代码文件名:AL6_7.C*/

/*功能:简单密码检测程序*/

#include "stdio.h"

main()

{char pass_str[80]; /*定义字符数组passstr*/

int I=0;

/*检验密码*/

while(1)

{clrscr();

printf("请输入密码\n");

gets(pass_str); /*输入密码*/

if(strcmp(pass_str,“password”)!=0) /*口令错*/

printf("口令错误,按任意键继续");

else

break; /*输入正确的密码,中止循环*/

getch();

I++;

if(I==3) exit(0); /*输入三次错误的密码,退出程序*/

}

/*输入正确密码所进入的程序段*/

}



4.拷贝字符串──strcpy()函数

(1)调用方式:strcpy(字符数组, 字符串)

其中“字符串”可以是串常量,也可以是字符数组。

(2)函数功能:将“字符串”完整地复制到“字符数组”中,字符数组中原有内容被覆盖。

(3)使用说明


1)字符数组必须定义得足够大,以便容纳复制过来的字符串。复制时,连同结束标志'\0'一起复制。

2)不能用赋值运算符“=”将一个字符串直接赋值给一个字符数组,只能用strcpy()函数来处理。


5.连接字符串──strcat()函数

(1)调用方式:strcat(字符数组, 字符串)

(2)函数功能:把“字符串”连接到“字符数组”中的字符串尾端,并存储于“字符数组”中。“字符数组”中原来

的结束标志,被“字符串”的第一个字符覆盖,而“字符串”在操作中未被修改。

(3)使用说明

1)由于没有边界检查,编程者要注意保证“字符数组”定义得足够大,以便容纳连接后的目标字符串;否则,会因

长度不够而产生问题。

2)连接前两个字符串都有结束标志'\0',连接后“字符数组”中存储的字符串的结束标志'\0'被舍弃,只在目标串


的最后保留一个'\0'。


6.求字符串长度──strlen()函数(len是length的缩写)

(1)调用方式:strlen(字符串)

(2)函数功能:求字符串(常量或字符数组)的实际长度(不包含结束标志)。


7.将字符串中大写字母转换成小写──strlwr()函数

(1)调用方式:strlwr(字符串)

(2)函数功能:将字符串中的大写字母转换成小写,其它字符(包括小写字母和非字母字符)不转换。


8.将字符串中小写字母转换成大写──strupr()函数

(1)调用方式:strupr(字符串)

(2)函数功能:将字符串中小写字母转换成大写,其它字符(包括大写字母和非字母字符)不转换。


C语言是通过函数来实现模块化程序设计的。所以较大的C语言应用程序,往往是由多个函数组成的,每个函数分别对应

各自的功能模块。

2008年1月8日星期二

几个关于zlib的小程序

#include
#include "/zlib/include/zlib.h"

// Demonstration of zlib utility functions

unsigned long file_size(char *filename)
{
FILE *pFile = fopen(filename, "rb");
fseek (pFile, 0, SEEK_END);
unsigned long size = ftell(pFile);
fclose (pFile);
return size;

}

int decompress_one_file(char *infilename, char *outfilename)
{
gzFile infile = gzopen(infilename, "rb");
FILE *outfile = fopen(outfilename, "wb");
if (!infile || !outfile) return -1;

char buffer[128];
int num_read = 0;
while ((num_read = gzread(infile, buffer, sizeof(buffer))) > 0)
{
fwrite(buffer, 1, num_read, outfile);

}

gzclose(infile);
fclose(outfile);

}

int compress_one_file(char *infilename, char *outfilename)
{
FILE *infile = fopen(infilename, "rb");
gzFile outfile = gzopen(outfilename, "wb");
if (!infile || !outfile) return -1;

char inbuffer[128];
int num_read = 0;
unsigned long total_read = 0, total_wrote = 0;
while ((num_read = fread(inbuffer, 1, sizeof(inbuffer), infile)) > 0)
{
total_read += num_read;
gzwrite(outfile, inbuffer, num_read);

}
fclose(infile);
gzclose(outfile);

printf("Read %ld bytes, Wrote %ld bytes,
Compression factor %4.2f%%\n",
total_read, file_size(outfilename),
(1.0-file_size(outfilename)*1.0/total_read)*100.0);

}


int main(int argc, char **argv)
{
compress_one_file(argv[1],argv[2]);
decompress_one_file(argv[2],argv[3]);

}

zlib dll包的使用

将zlib.h,zconf.h,zlib.lib三个文件拷到当前project的目录下,在stdafx.h中加入:
#define ZLIB_DLL
#include "zlib.h"//zconf.h

编译后,在c:\windows\system32中会自动生成一个zlib.dll文件。

注意:zlib version ist 1.1.3

zlib(integrity check)解压文件完整性检查 方案一:(未决)

压缩包文件: apollo.mdb.gz
解压文件: apollo.mdb
目的: 测试解压后的文件是否完整

方案一:
将apollo.mdb压入一个临时.gz文件apollo_tmp.mdb.gz,通过gzread()将apollo.mdb.gz与apollo.mdb进行比较。

代码:
BOOL CPublic::checkZippedFile(LPCTSTR sNameZipped, CString sNameExpand)
{
CString tempFile(ApoWorkDir + "\\apollo_tmp.mdb.gz");
gzFile pFileZipped;
gzFile pFileExpand;
HANDLE hFile;
//LPOFSTRUCT lpReOpenBuff;
int nReadedZipped;
int nReadedExpand;

//voidp pBufZipped;
//voidp pBufExpand;
char pBufZipped[1024];
char pBufExpand[1024];
CString strZip;
CString strExp;
//DWORD nDone;
//BOOL bSuccess;
CString sTmp;

//----compress the to be checked datei


if (!tempFile.IsEmpty())
{
DeleteFile(tempFile);
hFile = CreateFile(tempFile, GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
// FH 10.12.2004
if (hFile == INVALID_HANDLE_VALUE)
hFile = NULL;
//
if (hFile == NULL)
{
AfxMessageBox("Create ExpandFile "+ tempFile + " failed");
sNameExpand.Empty();
}
}
//fclose(hFile);
//hFile = NULL;

FILE *infile = fopen(sNameExpand, "rb");
gzFile outfile = gzopen(tempFile, "wb");

if (!infile || !outfile)
{
AfxMessageBox("open failed");
return false;
}
char inbuffer[1024];
int num_read = 0;
unsigned long total_read = 0, total_wrote = 0;
while ((num_read = fread(inbuffer, 1, sizeof(inbuffer), infile)) > 0) {
total_read += num_read;
gzwrite(outfile, inbuffer, num_read);
}

fclose(infile);
gzclose(outfile);
AfxMessageBox("Create ExpandFile" + tempFile);
//----

/*
* gzopen returns NULL if the file could not be opened or if there was
* insufficient memory to allocate the (de)compression state; errno
* can be checked to distinguish the two cases (if errno is zero, the
* zlib error is Z_MEM_ERROR).
*/
pFileZipped = gzopen(sNameZipped, "rb");
pFileExpand = gzopen(tempFile, "rb");

CString s;
s.Format("%d", pFileExpand);
AfxMessageBox(s);
if (pFileZipped && pFileExpand)
{
AfxMessageBox("begin to check integrity");

int nLoops = 0;

//---- read from source file
/*
* gzread returns the number of uncompressed bytes actually read (0 for
* end of file, -1 for error).
*/
nReadedZipped = gzread(pFileZipped, pBufZipped, sizeof(pBufZipped)); //how large is BUFFER_SIZE:10MB
nReadedExpand = gzread(pFileExpand, pBufExpand, sizeof(pBufExpand));


if (nReadedZipped != -1)
{
while (nReadedZipped != 0)
{
//if ((nLoops % 20) == 0)
// pDLT->pParent->PostMessage(pDLT->nMsgWatchdog, ++nWatchdog, 0);

//if (!sNameExpand.IsEmpty())
// WriteFile(hFile, pBuf, nReaded, &nDone, NULL);


if (nReadedZipped != -1 && nReadedZipped != 0)
{
strZip.Format("%s", pBufZipped);
strExp.Format("%s", pBufExpand);
if (strZip != strExp )
return false;

}

AfxMessageBox(strZip + "\n" + strExp);
//go on reading
nReadedZipped = gzread(pFileZipped, pBufZipped, sizeof(pBufZipped));
nReadedExpand = gzread(pFileExpand, pBufExpand, sizeof(pBufExpand));
if (nReadedZipped == -1 || nReadedZipped == 0)
return false;
AfxMessageBox("break5");
}
}
//----

// if (hFile)
// CloseHandle(hFile);
gzclose(pFileZipped);
gzclose(pFileExpand);
/* if ((nReaded == -1) || (gzclose(pFileZipped) != Z_OK))
{
bSuccess = FALSE;
sTmp.Format("zipped File %s is corrupt", sNameZipped);
// PROTOCOL_ENTRY(0,0,sTmp)

//if (!DeleteFile(sNameZipped))
//PROTOCOL_ENTRY(0,0,"Delete CompressedFile failed")

if ( !sNameExpand.IsEmpty() )
{
if ( !DeleteFile(sNameExpand) )
PROTOCOL_ENTRY(0,0,"Delete ExpandFile failed");
}
return false;
}*/
}
if (!tempFile.IsEmpty())
{
DeleteFile(tempFile);
}
return true;
}

2008年1月4日星期五

Problem:header datei CUnpackView.h nicht gefunden vc++

Kommisch sache, in MFC-Klass-assistent enthählt die Class CUpackView nicht , zwar Dialog Komponenten verbindet sich mit CView nicht mehr. mit Rarf viel mal versucht, die Datei steht ewig in Project aber nicht gehört zu MFC-Klass-assistent. leztmal wurde lösung gefunden, blöd aber wirksam:
Schneide die Datei UnpackView.h und UnpackView.cpp aus project, erzeuge eine neue Class CUnpackView durch MFC-Klass-assistent, dann kopieren Sourcekordierung aus altere UnpackView ins neu Datei. erledigt!!!

2008年1月3日星期四

SHBrowseForFolder设置初始目录中CALLBACK函数的使用

目的:
通过BROWSEINFO,SHBrowseForFolder打开Directory对话框,并且通过int CALLBACK BrowseCallbackProc()设置初始目录.

(源代码)打开目录选择对话框:
void CUnpackView::OnButtonPath(CDataExchange* pDX)
{
// TODO: Add your control notification handler code here
char dispname[MAX_PATH];
char copytopath[MAX_PATH];


BROWSEINFO bi;
ITEMIDLIST *pidl;

bi.hwndOwner = 0;
bi.pidlRoot = 0; //set the default browser path
bi.pszDisplayName = dispname;
bi.lpszTitle = "Verzeichniss auswählen";
bi.ulFlags = BIF_STATUSTEXT;//BIF_RETURNONLYFSDIRS;
bi.lpfn = BrowseCallbackProc; //调用回调函数
bi.lParam = 0;
bi.iImage = 0;



if ((pidl = SHBrowseForFolder(&bi))!=NULL) //
{
memset(copytopath, 0, MAX_PATH);
SHGetPathFromIDList(pidl, copytopath);//copytopath
//
sourceDir = (CString) copytopath;


}
//OnInitialUpdate();
UpdateData(false);
Invalidate();

if ( plc.checkFolder((LPCTSTR)sourceDir) )
{
openedSourceDir = (LPCTSTR)sourceDir;

//--get the LastWriteTime of folder/files
WIN32_FIND_DATA ffd ;
HANDLE hFind = FindFirstFile(openedSourceDir,&ffd);
SYSTEMTIME stUTC, stLocal;
FileTimeToSystemTime(&(ffd.ftLastWriteTime), &stUTC);
SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);
myTime.Format("%d. %d %d, %d:%d", stLocal.wDay,stLocal.wMonth,stLocal.wYear,stLocal.wHour,stLocal.wMinute);
//--
d_ColorStatic.SetWindowText((LPCTSTR)myTime);


GetDlgItem(IDC_BUTTON_ROLLBACK)->EnableWindow(true);
GetDlgItem(IDC_BUTTON_REPORT)->EnableWindow(true);
GetDlgItem(IDC_STATIC_STATUSTITLE)->EnableWindow(false);

}
else
{
GetDlgItem(IDC_BUTTON_ROLLBACK)->EnableWindow(false);
GetDlgItem(IDC_BUTTON_REPORT)->EnableWindow(false);
GetDlgItem(IDC_STATIC_STATUSTITLE)->EnableWindow(false);
AfxMessageBox("Die angegebene Verzeichniss ist nicht richtig, bitte versuchen Sie nochmal.");

}

}


(源代码)CALLBACK函数:
在.h中:

CString sicherungDir;
static int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData);



在.cpp中:
int CALLBACK CUnpackView::BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
//CALLBACKSTRUCT * cs = (CALLBACKSTRUCT*) lpData;

CString dir(_T(""));
BOOL hasInitial = false;
// * Statische Member-Funktionen haben keinen this-Zeiger: *
// * this does not work, because the pUnpack is a new obj,
// * pUnpack->openedSourceDir is the new one

//---- use the View pointobject
CMDIFrameWnd *pFrame = (CMDIFrameWnd*)AfxGetApp()->m_pMainWnd;
CMDIChildWnd *pChild = (CMDIChildWnd *) pFrame->GetActiveFrame();
CUnpackView *pView = (CUnpackView *) pChild->GetActiveView();
//--

if ( pView->openedSourceDir != "")
dir = pView->openedSourceDir; // the default stays at the opened folder failed!because pView is a new pObject

else
dir = CPublic::sSicherungDir; //if first time to open the folder dialog


/////////////////////////////////////////////////
//'d:\\' can not be recognised by SHGetPathFromIDList()
// must be changed into 'd:\'
/////////////////////////////////////////////////
dir.Replace("\\\\","\\");

switch(uMsg)
{
case BFFM_INITIALIZED: //initial
hasInitial =true;
::SendMessage(hwnd,BFFM_SETSELECTION,TRUE,(LPARAM)(LPCTSTR)dir ); //"d:\\datenversicherung"
//AfxMessageBox("BFFM_INITIALIZED");

break;

case BFFM_SELCHANGED: //path changed
{
/////////////////////////////////////////////
// to avoid SHGetPathFromIDList()twice running
// before "case BFFM_INITIALIZED" has been done
////////////////////////////////////////////
if (hasInitial)
{
char curr[MAX_PATH];

SHGetPathFromIDList((LPCITEMIDLIST)lParam,curr);

CString s;
s.Format("BFFM_SELCHANGED, curr: %s",curr);
AfxMessageBox(s);

if(curr[strlen(curr)-1]==92)
sprintf(curr,"%s",curr);
else
sprintf(curr,"%s\\",curr);

::SendMessage(hwnd,BFFM_SETSTATUSTEXT,0,(LPARAM)curr);

}

}
break;

}
return 0;

}


注意:
在对CALLBACK函数的使用中,必须是类的静态成员函数。
否则,用MS编译器,会得到这个编译错误:
error C2664: 'Bubblesort' : cannot convert parameter 4 from 'int (__stdcall CCallbackTester::*)(const unsigned char *,const unsigned char *)' to 'int (__stdcall *)(const unsigned char *,const unsigned char *)' There is no context in which this conversion is possible


参考:
Visual C++中回调函数使用的变身大法
回调函数指南(Callback Functions Tutorial)
How to Implement Callbacks in C and C++

VC++获取文件修改时间

WIN32_FIND_DATA结构

  关于文件的全部属性信息,总计有以下以下9 种:文件的标题名、文件的属性(只读、存档,隐藏等)、文件的创建时间、文件的最后访问时间、文件的最后修改时间、文件大小的高位双字、文件大小的低位双字、保留、保留。在这里只有文件标题名和文件的长度可以通过CFile类比较方便的获得,而对于其他几种属性的获取和设置就无能为力了。

  在用findfirst()和findnext()函数去查找磁盘文件时经常使用的一个数据结构WIN32_FIND_DATA的成员变量里包含了以上所有的文件属性,因此可以通过这个结构作为获取和更改文件属性的手段。该结构的内容如下:
typedef struct _WIN32_FIND_DATA {
  DWORD dwFileAttributes; //文件属性
  FILETIME ftCreationTime; // 文件创建时间
  FILETIME ftLastAccessTime; // 文件最后一次访问时间
  FILETIME ftLastWriteTime; // 文件最后一次修改时间
  DWORD nFileSizeHigh; // 文件长度高32位
  DWORD nFileSizeLow; // 文件长度低32位
  DWORD dwReserved0; // 系统保留
  DWORD dwReserved1; // 系统保留
  TCHAR cFileName[ MAX_PATH ]; // 长文件名
  TCHAR cAlternateFileName[ 14 ]; // 8.3格式文件名
} WIN32_FIND_DATA, *PWIN32_FIND_DATA;

可以通过FindFirstFile()函数根据当前的文件存放路径查找该文件来把待操作文件的相关属性读取到WIN32_FIND_DATA结构中去:
WIN32_FIND_DATA ffd ;
HANDLE hFind = FindFirstFile("c:\\test.dat",&ffd);

在使用这个结构时不能手工修改这个结构中的任何数据,结构对于开发人员来说只能作为一个只读数据,其所有的成员变量都会由系统完成填写。

实例
//--get the LastWriteTime of folder/files
WIN32_FIND_DATA ffd ;
HANDLE hFind = FindFirstFile(openedSourceDir,&ffd);
SYSTEMTIME stUTC, stLocal;
FileTimeToSystemTime(&(ffd.ftLastWriteTime), &stUTC);
SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);
myTime.Format("%d. %d %d, %d:%d", stLocal.wDay,stLocal.wMonth,stLocal.wYear,stLocal.wHour,stLocal.wMinute);
//--
d_ColorStatic.SetWindowText((LPCTSTR)myTime);

2008年1月2日星期三

修改MFC标题栏上的图标

HICON m_hIcon;


在MainFrm的OnCreate()里
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon