VC++6.0 MFC编程心得小结

作为一个正经的科班出身软件工程专业者,想必都知道什么是VC++6.0。这个充满神奇的工具。而作为专业教学课的首选编程IDE,它有着不可撼动的地位。博主不知道别家院系使用何种启蒙工具,反正博主就是这个工具启蒙的。对它,有着又爱又恨得情怀。

数据库

一个程序的最基本功能有输入、查询、修改、删除、保存、打印,均与数据库有关。而对数据库的基本操作使用最频繁,以Access 为例:

1、用程序创建Access 数据库文件:

手工创建数据文件的方法大家并不陌生,如果用程序创建有时候也需要,下面就是其中一种方法,可以使用ADOX::CatalogPtr来创建mdb文件。用下面“配置设置文件”文件方法设置数据库的参数,配置数据文件的名称、密码、ID和路径,在有安装程序的情况下需要它。

ADOX的建库,它是在没有数据库文件的情况下,用ADOX的目录指针CatalogPtr来创建ACCESS数据库文件,如下:

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
BOOL CRecord::UseADOXCatalogPtrCreatAccessDB()

{

CString str=DBPath + DBName; //数据库的路径和名称

CString strPassword=DBPasswd; //数据库的密码

CString strcnn=_T("Provider=Microsoft.JET.OLEDB.4.0;Data source ="+str+";\

Jet OLEDB:DatabasePassword="+strPassword); //数据库的字串



//使用ADOX::CatalogPtr来创建mdb文件:

HRESULT hr = S_OK;

hr=::CoInitialize(NULL);

if(SUCCEEDED(hr))

{

HRESULT hr = S_OK;

try

{

ADOX::_CatalogPtrm_pCatalog = NULL;

hr=m_pCatalog.CreateInstance(__uuidof(ADOX::Catalog));

if(FAILED(hr))

{

_com_issue_error(hr);

}
else{

m_pCatalog->Create(_bstr_t(strcnn));//Create MDB

}

}catch(_com_error e) //异常处理

{//错误显示}

}

::CoUninitialize();

return TRUE;

}

2、用程序在系统中创建Access的数据源名称DSN:

手工配置ODBC的数据源名称,大家也不陌生。而通过程序动态建立ODBC的DSN,在有安装程序的情况下也需要它。它是在已有数据库文件的情况下建立数据源名称。

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
28
29
30
31
32
33
BOOL CRecord::CreatAccessDSN()

{

CString DBID ,lpszFile=DBPath+DBName;

int mlen;

char* szDesc=new char[512];

sprintf(szDesc,"DSN=%s?UID=%s?;PWD=%s?;DESCRIPTION=;?DBQ=%s?\

FIL=MicrosoftAccess?DEFAULTDIR=%s??"\

,DBName,DBID,DBPasswd,lpszFile,DBPath);

mlen=strlen(szDesc);

for(int i=0;i<mlen;i++)

{

if(szDesc[i]=='?') szDesc[i]='\0';

}

if(SQLConfigDataSource(NULL,ODBC_ADD_DSN,"MicrosoftAccess\

Driver (*.mdb)\0", (LPCSTR)szDesc)) return TRUE;

……

}

3、动态建数据库表

一种方法可以通过一个配置数据库表的txt文件,它包括创建数据表的SQL语句,程序读入该文件的,并分析该文件的内容,得到一SQL字串,进行创建,这种方法建表比较灵活;另一种方法也可以通过有包括创建Access数据表SQL语句的程序代码创建。两种创建方法都要注意在字段名与它的字段类型之间必需用tab键隔开。如下,采用后者:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
try

{

VARIANT* RecordsAffected=0;

CString strSQL=\

"CREATE TABLE accesstable(ID longinteger ID ENTITY(1,1) not null,";

strPSW=strPSW+"name text(10)not null,";

strPSW=strPSW+"cash DOUBLE,remark text(100));"; //SQL字串

m_pCon->Execute((_bstr_t)(LPCTSTR)strSQL,NULL,adExecuteNoRecords);

}

catch(_com_error&e) { …… }

用VC++程序来动态建库很多数据类型不支持,但表名、字段名可以是变量。

4、数据库的连接和关闭

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
bool CRecordSonPrg::CreatConnect()   //数据库的连接

{

CString str="Provider=MSDASQL.1;Password='"+DBPasswd+"';\

PersistSecurity Info=True;Data Source="+DBName; //连接字串

try

{

m_pCon.CreateInstance(__uuidof(Connection));

m_strConnection = _T(str);

intbCon=m_pCon->Open(_bstr_t(m_strConnection),"","",adConnectUnspecified);

}

catch(_com_error &e) { …… }

return true;

}

void CRecordSonPrg::CloseConnect() //数据库的关闭

{

try

{

m_pCon->Close(); //关闭连接

m_pCon.Release(); //释放

}

catch(_com_error &e){ …… }

}

5、用ADO对数据库记录的增、删、改、存、查、排序、过滤、打印

1
2
3
4
5
6
7
//打开一个数据表DBtable

m_pRs.CreateInstance(__uuidof(Recordset));

m_strCmdText= _T("DBtable");

m_pRs->Open((LPCTSTR)m_strCmdText,(LPCTSTR)m_strConnection,adOpenStatic,adLockOptimistic,adCmdTable);

①增加记录:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
try

{

if(!m_pRs->Supports(adAddNew))return false;

m_pRs->AddNew();

m_pRs->Fields->GetItem("user")->Value=(_variant_t)strm_newuser;

……

m_pRs->Update();

}

②删除记录:

1
2
3
4
5
6
7
try

{

m_pRs->Delete(adAffectCurrent ); //删除当前记录

}

③改动、保存记录:

1
2
3
4
5
6
7
8
9
10
11
void CRsCgDlg::SaveModifiedRecord()       //记录修改后保存

{

…… //拷贝对话框数据到ADOC++ 绑定成员

//调用ADO数据绑定更新模式的接口

HRESULT hr = m_piAdoRecordBinding->Update( (CADORecordBinding*)this );

}

④查找记录:

1
2
3
4
5
6
7
8
9
CString temp ="user='"+m_FindUserName+"'";  

//查找字串

_bstr_ttemp1=(_bstr_t)temp;

//类型转换为_bstr_t

m_pRs->Find(temp1,0,adSearchForward,"");

⑤排序记录:

1
2
3
4
5
6
7
8
9
10
11
12
13
CString temp="’user,"+m_FindUserName+"'";  

//排序字串

_bstr_ttemp1=(_bstr_t)temp;

//类型转换为_bstr_t

m_pRs->Sort=(temp1);

m_pRs->Sort=("");

//取消排序

⑥过滤记录:

1
2
3
4
5
6
7
8
9
CString strfilter = _T("name = '"+m_strFilter+"'");    

//过滤字串

m_pRs->Filter= (_variant_t)strfilter;

m_pRs->Filter= (long) adFilterNone;

//取消过滤

⑦打印记录:

打印记录可以采用CDocument类的serialize()文档类的方式,也可以借助显示控件实现。这里是用FlexGrid控件编写的打印代码。

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
void CMyApp::PrintToText()

{

CString cFilePath = "C:\\Documents and Settings\\Administrator\\";

CString cFileName = "打印统计表.txt";

CString cFile = cFilePath+cFileName;

CStdioFile file;

//CStdioFile类是CFile类的派生类,它是以流方式操作文本

file.Open(cFile,CFile::modeCreate|CFile::modeWrite|CFile::typeText)

CString str;

str.Format("%s\n\n",cFileName);

//格式化文件主题

file.WriteString(str);

//写入文件主题

int RowCount = m_MSFGrid.GetRows();

//从FlexGrid控件表取行数

int ColCount = m_MSFGrid.GetCol();

//从FlexGrid控件表取列数

for(long r=0;r<RowCount;r++) //行循环

{

for(long c=0;c<ColCount;c++) //列循环

{

CString Matrix =m_MSFGrid.GetTextMatrix(r,c);

//得到r行c列的文本

switch(c)

{ str.Format( …… );//产生打印格式 }

file.WriteString(str);

}

}

file.SetLength(file.GetPosition());

//设置文件长度

file.Close();

//关闭文件

str="notepad "+cFile;

WinExec(str,SW_SHOW);

//利用记事本打开生成的文本文件

}

6、配置设置文件:

为了增加程序的灵活性,对配置文件的读、写也是必要的。Windows操作系统专门为此提供了6个API函数来对配置设置文件进行读、写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
GetPrivateProfileInt()               

//从私有初始化文件获取整型数值

GetPrivateProfileString()

//从私有初始化文件获取字符串型值

GetProfileInt

//从win.ini获取整数值

GetProfileString

//从win.ini获取字符串值

WritePrivateProfileString

//写字符串到私有初始化文件

WriteProfileString

//写字符串到win.ini

下面采用私有初始化文件获取或写入字符串型值的函数来读写配置文件:

读文件:

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
28
29
30
CString CMyApp::GetOneIniData(CString sFilePath)

{

CString str;

char buf[256] =NULL;

int len=0;

len = GetPrivateProfileString(

"Custom", //节名

"UserName" //项名

"No", //没找到此项时的返回值

buf, //目标缓冲区地址

256, //目标缓冲区长度

sFilePath //配置文件的准确路径

);

str=buf;

return str;
}

写文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
BOOL CKaApp::WriteIniData(CString cstr,CString strUserName)

{

CString sFile = cstr;

CFileStatus status;

BOOL RetUser=WritePrivateProfileString(

"Custom", //节名

"UserName", //项名

strUserName, //内容

sFile //配置文件的准确路径

);

return TRUE;

}

对于SQL Server的操作类似。