------------------------------------------------------
1. EDB資料庫的結構
------------------------------------------------------
EDB資料庫的基本機關是Volume,也就是卷,通常存在于一個磁盤檔案中,例如:pim.vol等等。
在卷中包含若幹資料庫,可以由資料庫名稱或者OID(對象編号)來通路他們,例如:pim.vol中包含名為“Appointments Database”的資料庫,其OID為1077960704。
而每個資料庫包含很多記錄,可以通過OID或者在資料庫中的排序标号來通路每個記錄。
每個記錄又包含很多屬性,記錄屬性==記錄資料。記錄的屬性由CEPROPVAL類型的結構來存儲,每個記錄存儲一個CEPROPVAL類型的數組,數組大小就是屬性數量。
每個記錄的屬性由CEPROPVAL::propid來辨別。propid是一個雙字類型(DWORD)的資料,高位字定義的是屬性名稱ID,低位字代表 資料庫中記錄的屬性資料的類型,如:LPWSTR,UI4等等。其中PIM.VOL中的屬性ID定義在"pimstore.h"中。
屬性的資料則存儲在CEVALUNION類型的聯合(union)中,CEVALUNION的定義如下:
typedef union _CEVALUNION {
short iVal; //@field CEVT_I2
USHORT uiVal; //@field CEVT_UI2
long lVal; //@field CEVT_I4
ULONG ulVal; //@field CEVT_UI4
//@field CEVT_AUTO_I4_
FILETIME filetime; //@field CEVT_FILETIME
LPWSTR lpwstr; //@field CEVT_LPWSTR - Ptr to null terminated string
CEBLOB blob; //@field CEVT_BLOB - DWORD count, and Ptr to bytes
//@field CEVT_AUTO_I8
//@field CEVT_RECID
//@field CEVT_STREAM
BOOL boolVal; //@field CEVT_BOOL
double dblVal; //@field CEVT_R8
} CEVALUNION, *PCEVALUNION;
【總 結】 實際上,資料庫就是一個表,表中各行就是記錄,每個記錄存儲很多不同類型的資料,比如:在記錄OID=234裡面,存儲了小王(姓名)、男(性别)、安徽 (籍貫)...。表最頂上的一行,也就是表頭,存儲的就是屬性的propid,代表屬性類型,例如:建立資料庫時,可以指定姓名的 PropID=0x0012001f,性别的PropID=0x0013001f等等。将來打開資料庫時,可以根據表頭,也就是propid來通路想要的 屬性,也可以根據propid指定排序的規則,例如:是依據姓名(0x0012001f)排序還是依據籍貫(0x0013001f)排序。
------------------------------------------------------
2. 如何讀取資料庫
------------------------------------------------------
Step 1: 要載入資料庫所在的卷(Volume)
調用CeMountDBVolEx()載入指定的資料庫檔案,并且得到資料庫檔案的GUID,例如:CEGUID m_sDBGuid。
Step2: 建立資料庫會話
調用CeCreateSession(m_sDBGuid),由此得到會話的句柄HANDEL se;
Step3:打開卷中想要通路的資料庫
調用CeOpenDatabaseInSession()打開資料庫。
可以設定該函數的形參“SORTORDERSPECEX* pSort”指定排序規則。以後在調用CeSeekDatabaseEx()移動記錄指針并通路資料庫時,将遵循此規則。
必 須注意的是,pSort結構的通路規則必須在資料庫的通路規則中存在,也就是說,pSort指向的結構中,wNumProps、wKeyFlags、 rgPropID[]數組中的propid必須和資料庫屬性中存儲的某一個排序規則保持嚴格一緻【注:資料庫在建立時,會指定一個 CEDBASEINFOEX類型的結構,該結構中,CEDBASEINFOEX::rgSortSpecs[16]指定的是 SORTORDERSPECEX 類型的數組,也就是說,資料庫可以有最多16種排序規則,這些規則存儲于資料庫中】。在打開資料庫時,隻需要選擇其中一種排序規則,且排序規則必須和建立 資料庫時保持一緻,不能出現資料庫中沒有的propid。并且對于EDB而言,SORTORDERSPECEX::wVersion必須等于2!如果這些 準則沒有滿足,則CeOpenDatabaseInSession()函數傳回INVALID_HANDLE_VALUE。
Step4:讀取資料庫記錄
資料庫中有一個記錄指針,CeReadRecordPropsEx()函數讀取的就是記錄指針處的記錄屬性。要使記錄指針指向想要通路的記錄,也就是調用 CeSeekDatabaseEx()函數搜尋資料庫的記錄集,并使記錄指針指向搜尋結果,可以有很多種搜尋方法,例如:輸入 CEDB_SEEK_CEOID,根據指定的OID搜尋,輸入CEDB_SEEK_BEGINNING,從資料庫第一個元素搜尋位于偏移量為 dwValue的記錄。
CeReadRecordPropsEx()将傳回記錄屬性數組的頭指針,如前所述,該數組是CEPROPVAL類型,我們根據propid确定屬性的資料類型,再從CEVALUNION類型的資料讀取屬性值。
具體而言,采用CeReadRecordPropsEx()函數讀取屬性時,該函數的形參“lplpBuffer”傳回的是CEPROPVAL類型的數組 的頭指針,rgPropID[]存儲的是要讀取的屬性的PropID,也就是指定客戶需要讀取那些屬性,由于客戶一次可能讀取很多屬性,是以 rgPropID[]是個數組,而形參lpcPropID則指定使用者需要讀取的屬性數目,當lpcPropID=0時,代表讀取該記錄的全部屬 性,lpcPropID在CeReadRecordPropsEx()函數傳回時被指派,代表讀取的屬性數量。
------------------------------------------------------
3. 如何列舉并讀取資料庫屬性
------------------------------------------------------ 如前所述,一個卷包含若幹資料庫,我們可以枚舉各個資料庫,并且讀取他們的屬性。
Step 1:載入資料卷
調用CeMountDBVolEx()函數。
Step 2: 得到枚舉環境句柄
調用CeFindFirstDatabaseEx()函數,得到一個句柄,該句柄作為CeFindNextDatabaseEx()函數的輸入,構成枚舉環境。
Step 3: 枚舉資料庫
調用CeFindNextDatabaseEx()函數枚舉資料庫,移動資料庫指針,并且得到目前資料庫的OID。枚舉時采用while(){}循環,循環中斷依據就是資料庫oid==0。例如:
while((oid=CeFindNextDatabaseEx(se,0))!=0)
{
//TODO: Add your code here:
};
Step 4: 讀取資料庫資訊
調用CeOidGetInfoEx2()函數,依據oid讀取資料庫資訊。其實該函數可以根據oid得到資料庫、檔案、路徑和記錄等很多種對象的資訊。在調用該函數時,可能出現調用堆棧被清空的問題,這是數組越界所緻,是沒有#define EDB造成的。
資料庫的屬性存儲在CEOIDINFOEX::infDatabase成員中,該成員是CEDBASEINFOEX類型,其詳細的含義見MSDN。