1、几点说明:
I、do{}while(FALSE);这个代码块在本文所附代码中随处可见。通常写法如下:
- do
- {
- if(! XXXX)
- {
- break;
- }
- if(! XXXX)
- {
- break;
- }
- ...
- }while(FALSE);
复制代码
这种写法是为了避免判断语句过多 if() 嵌套过多导致代码不清晰,
if()嵌套写法如下。
- if()
- {
- if()
- {
- if()
- {
- ....
- }
- }
- }
复制代码
当然,也可以使用 goto,但结构化程序设计并不提倡 goto。goto写法如下
- if(! XXXX)
- {
- goto _label
- }
- if(! XXXX)
- {
- goto _label
- }
- ....
- _lable:
复制代码
II、单例模式:单例模式也是本文所附代码常用的一种方法。
单例模式写法如下:
- class XXXX
- {
- private:
- class CGarbo
- {
- public:
- CGarbo()
- {
- ....
- }
- ~CGarbo()
- {
- ....
- }
- };
- //把内嵌类定义为friend,是为了支持VC6,
- //vc2008支持的 c++ 标准不需要定义为friend
- friend class CGarbo;
- static CGarbo m_Garbo;
- }
复制代码
为什么要用单例模式?因为我们在程序里经常会遇到一些
必须执行且仅需要执行一次的代码,这时,我们就可以用
单例模式把这些代码封装起来。拿程序中的 GdiPlus 为例。
在使用GdiPlus对象之前必须初始化GdiPlus
- Gdiplus::GdiplusStartup(&m_gdiplusToken,&m_gdiplusStartupInput,NULL);
复制代码
使用完毕后必须释放GdiPlus
- Gdiplus::GdiplusShutdown(m_gdiplusToken);
复制代码
这时候,我们就可以用单例模式把这两个函数封装起来。
当然,如果你不喜欢单例模式,也可以显示调用这两个函数。
III、strcpy 与 strcpy_s、sprintf 与 sprintf_s
在VC6里头没有 strcpy_s 与 sprintf_s 函数,
为了避免破坏栈,微软在后来的版本中用一系列加了_s的函数
代替了原来的函数,当然,原来的函数还是可以用,不过编译
时会有警告。
IV、本文所附代码里用到了 stl 的 string 和 Gdiplus
代码的写法是std::string XXXX; Gdiplus::XXXX();
(每处使用都在前面加了命名空间)
而不是 using namespace std;
using namespace Gdiplus;
为什么?我也不是很清楚,不过据说,using namespace XXXX 并不是
一个好的编码习惯。
V、Gdiplus。VC6并不支持Gdiplus,所以需要下载Gdiplus的.H文件和.Lib文件
附件里包涵了Gdiplus的 .H 和.Lib,放置在VC6工程目录之外即可。
ConvertImage.H头文件里做了预处理。
VI、关于数据库
本代码测试了Access 以及 mysql数据库
其中Access数据库的 float 字段写入失败,mysql成功。
Access数据库用 OLE对象 来存储二进制文件
mysql数据库用 BOLB 来存储二进制文件,用 LONGBLOB 可存储1G大小的文件。
2.图像文件的操作
跟图像文件相关的几个类
Class CCaptureScreen;
截取屏幕图像类,提供一个公共函数
BOOL CaptureImage(CBaseBitmap & bmp,const RECT & rc);
将指定区域内的屏幕图像数据截取到 CBaseBitmap 对象中
函数里默认将图像截取为24位图像,
Class CHeapMemory; 内存管理类,管理 new,delete 内存
为什么要这个类?提供给 CConverImage 使用
Class CGlobalMemory; 内存管理类,管理 GlobalAlloc,GlobalFree 分配的内存
为什么要这个类?提供给 CConverImage 使用。
CGlobalMemory 和 CHeapMemory 提供的对外接口是一样的。
为什么有了CHeapMemory,还要这个CGlobalMemory?
因为Gdiplus 操作内存图像数据总是用到 IStream 对象,也就是说,
Gdiplus总是从一个 IStream 对象中读取图像数据或者总是将图像数据写
到一个 IStream 对象中去。而微软提供的 IStream 对象的唯一来源就是
API : CreateStreamOnHGlobal(HGLOBAL,BOOL,IStream *)
从一个 Global 句柄上生成一个 IStream 对象,Global 句柄可以为NULL。
据MSDN上说:GlobalAlloc 系列函数是为了兼容 Win16,现在都Win64了,
难道我们还要用Win16?所以,在CGlobalMemory 之后又有了 CHeapMemory。
但事实上,在操作大文件的时候,CGlobalMemory 的速度是优于 CHeapMemory 的。
CHeapMemory 与 CGlobalMemory 都重载了操作符 const char * 与
const unsigned char * 用于返回分配的内存的常量指针。
operater const char * ();
operater const unsigned char * ();
这样,我们就可以在对象外对分配的内存进行读访问。
但是C/C++提供了强制类型转换(这应该是C/C++最被诟病的地方)
我们可以通过 (char *) 或 const_cast<char *>()将 const 属性去掉。
然后,我们的封装就变成了扯淡。
当然,我们可以不提供这样的界面,转而写成这样。
ReadBuffer();
WriteBuffer();
然后,我们就必须先分配一段内存,然后把这段内存写入对象,或是从对象
中读取数据到内存里。我觉得,这么做有点脱裤子放屁。
Class CConvertImage; 封装Gdiplus类
私有的构造函数,不提供生成对象,所有接口都以 static 函数提供
将一个图像文件转换成指定格式的图像文件
ImageF2F();
将一个图像文件转换成指定格式并存储到 CGlobalMemory 对象中
ImageF2G();
将一个CGlobalMemory对象中的图像转换成指定格式的图像文件
ImageG2F();
将一个CGlobalMemory对象中的图像转换成指定格式并存储到
另一个 CGlobalMemory 对象中
ImageG2G();
将一个图像文件转换成指定格式并存储到 CHeapMemory 对象中
ImageF2H();
将一个CHeapMemory对象中的图像转换成指定格式的图像文件
ImageH2F();
将一个CHeapMemory对象中的图像转换成指定格式并存储到
另一个 CHeapMemory 对象中
ImageH2H();
Class CBaseBitmap;
我们要显示图像,就必须把图像转换成Bitmap图像,JPG,PNG,TIFF,GIF
等图像是不能直接显示的。这个类就是把其他格式的图像以Bitmap
的形式显示出来。
本类继承自 CHeapMemory ,当然,你可以把它改成继承自 CGlobalMemory
只需要几个很小的改动就成。
Bitmap图像格式如下:
BITMAPFILEHEADER 结构(bitmap 文件头)
BITMAPINFO 结构
点阵数据
显示图像的函数
void StretchBitmap(HDC hdc,const RECT & rc);
本函数是以缩放的方式显示图像,而缩放图像必然导致图像失真。
微软为我们提供了一个API来平滑缩放。
SetStretchBltMode(hdc,STRETCH_HALFTONE);
当然,这是要付出代价的,这个算法比较复杂,以这种方式显示
图像,CPU占用率是比较高的。
3、数据库操作
本文代码用ODBC API 操作数据库。为什么用ODBC API?因为我喜欢!
个人并不喜欢 mfc 封装的 ODBC 类,而ADO用来操作微软自己的ACCESS
或SQL-Server还不错,而用来访问别的数据库如 MYSQL 或者 Oracle
似乎也是基于 ODBC。
ODBC API 结构简述
SQLAllocHandle() 分配环境变量句柄
SQLAllocHandle() 用环境变量句柄分配数据库句柄
SQLConnect() 或 SQLDriverConnect() 用数据库句柄连接数据库
SQLAllocHandle() 用数据库句柄分配statement句柄
用 statement 句柄来执行 selct 、delete 、update 等语句
SQLFreeHandle() 释放statement句柄
SQLDisConnect() 断开数据库连接
SQLFreeHandle() 释放数据库句柄
SQLFreeHandle() 释放环境变量句柄
数据库相关的类
CCommonDB
用单例模式初始化环境变量句柄 和 数据库句柄
以 protect 方式提供的构造函数,在构造函数里连接数据库
以 protect 方式提供的析构函数,在析构函数里断开数据库连接
数据表 ImageTrn 的结构
typedef struct tagImageTrn
{
long index;
char desc[255];
TIMESTAMP_STRUCT dateTime;
long length;
float fTest;
double dTest;
}IMAGETRN,* LPIMAGETRN;
union用于定义所有数据表结构
typedef union tagTable
{
long none;
IMAGETRN IT;
}TABLE,* LPTABLE;
如果你有一个表 Table1
可以定义
typedef struct tagTable1
{
......
}TABLE1,*LPTABLE1;
typedef union tagTable
{
long none;
IMAGETRN IT;
TABLE1 T1;
}TABLE,* LPTABLE;
CDBAccess
继承自CCommonDB,用于初始化 statement 句柄
提供一系列 BindXXX 函数,将查询结构绑定到内存变量上
提供一系列 ParamXXX 函数,将输入参数绑定到内存变量上
提供一系列虚函数供子类重载
OpenRecordSet() ;查询
PrepareInsert() ;插入记录绑定参数
InsertRecord() ;插入记录
DeleteRecord() ;删除记录
UpdateRecord() ;更新记录
Data() ;取得查询结果
public 接口两个
GetNextRecord()
GetPrevRecord()
CImageTrn
对表ImageTrn 进行读写操作的类,继承自DBAccess
演示对数据库的访问。
几个成员变量的简单说明:
//用于SQLBindParameter 的最后一个参数
SQLINTEGER m_BindIn[MAX_FIELDS_OF_TABLE];
//用于SQLBindCol 的最后一个参数
SQLINTEGER m_BindOut[MAX_FIELDS_OF_TABLE];
//存储输入参数
TABLE m_tableIn;
//存储查询结果
TABLE m_tableOut;
可以定义一个具有全局生命期的对象 CImageTrn a;
这时,数据库就会自动连接,以后再定义CImageTrn对象,
都不会再去连接数据库。当a对象析构时,自动断开数据库
连接。
如果你有一个表 TableTest,要访问表 TableTest,则可以
仿照CImageTrn写一个CTableTest类。
|
|
|