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;
- }
復制代碼
為什么要用單例模式?因為我們在程序里經常會遇到一些
必須執(zhí)行且僅需要執(zhí)行一次的代碼,這時,我們就可以用
單例模式把這些代碼封裝起來。拿程序中的 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);
將指定區(qū)域內的屏幕圖像數據截取到 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,現(xiàn)在都Win64了,
難道我們還要用Win16?所以,在CGlobalMemory 之后又有了 CHeapMemory。
但事實上,在操作大文件的時候,CGlobalMemory 的速度是優(yōu)于 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() 分配環(huán)境變量句柄
SQLAllocHandle() 用環(huán)境變量句柄分配數據庫句柄
SQLConnect() 或 SQLDriverConnect() 用數據庫句柄連接數據庫
SQLAllocHandle() 用數據庫句柄分配statement句柄
用 statement 句柄來執(zhí)行 selct 、delete 、update 等語句
SQLFreeHandle() 釋放statement句柄
SQLDisConnect() 斷開數據庫連接
SQLFreeHandle() 釋放數據庫句柄
SQLFreeHandle() 釋放環(huán)境變量句柄
數據庫相關的類
CCommonDB
用單例模式初始化環(huán)境變量句柄 和 數據庫句柄
以 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類。
|
|
|