原文地址http://wuyuans.com/2011/12/safearray-type/
SAFEARRAY類型
我們將使用SAFEARRAY來通過COM傳送串行化的對象。這部分將介紹如何建立和使用SAFEARRAY類型。
SAFEARRAY是數據結構的一種。這種結構也沒有什麼特別的,你只需要正確地設置它,當然你要知道其中一些頗爲複雜的規定。爲了確保SAFEARRAY被正確地使用,它有一系列用作管理的API函數。這些API的函數負責創建、調整大小和刪除SAFEARRAY。不幸的是,有關這些API函數的文檔是相當少的。
對於SAFEARRAY的內部結構我們並不關心,但瞭解一下是值得的。以下就是SAFEARRAY的Win32定義:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
typedef struct
tagSAFEARRAY { unsigned short cDims; unsigned short fFeatures; unsigned long cbElements; unsigned long cLocks; void *
pvData; SAFEARRAYBOUND
rgsabound[ 1 ]; }
SAFEARRAY; |
這個結構的成員(cDims,cLocks等)是通過API函數來設置和管理的。真正的數據存放在pvData成員中,而SAFEARRAYBOUND結構定義該數組結構的細節。以下就是該結構成員的簡要描述:
成員 | 描述 |
cDims | 數組的維數 |
fFeatures | 用來描述數組如何分配和如何被釋放的標誌 |
cbElements | 數組元素的大小 |
cLocks | 一個計數器,用來跟蹤該數組被鎖定的次數 |
pvData | 指向數據緩衝的指針 |
rgsabound | 描述數組每維的數組結構,該數組的大小是可變的 |
rgsabound是一個有趣的成員,它的結構不太直觀。它是數據範圍的數組。該數組的大小依safe array維數的不同而有所區別。rgsabound成員是一個SAFEARRAYBOUND結構的數組–每個元素代表SAFEARRAY的一個維。
typedef struct tagSAFEARRAYBOUND
{
unsigned long cElements;
unsigned long lLbound;
} SAFEARRAYBOUND;
維數被定義在cDims成員中。例如,一個’C'類數組的維數可以是[3][4][5]-一個三維的數組。如果我們使用一個SAFEARRAY來表示這個結構,我們定義一個有三個元素的rgsabound數組–一個代表一維。
cDims = 3;
…
SAFEARRAYBOUND rgsabound[ 3 ];
rgsabound[0]元素定義第一維。在這個例子中ILBOUND元素爲0,是數組的下界。cElements成員的值等於三。數組的第二維([4])可以被rgsabound結構的第二個元素定義。下界也可以是0,元素的個數是4,第三維也是這樣。要注意,由於這是一個”C”數組,因此由0開始,對於其它語言,例如Visual Basic,或者使用一個不同的開始。該數組的詳細情況如下所示:
元素 | cElements | ILbound |
rgsabound[0] | 3 | 0 |
rgsabound[1] | 4 | 0 |
rgsabound[2] | 5 | 0 |
關於SAFEARRAYBOUND結構其實還有很多沒說的。我們將要使用的SAFEARRAY只是一個簡單的單維字節數組。我們通過API函數創建數組的時候,SAFEARRAYBOUND將會被自動設置。只有在你需要使用複雜的多維數組的時候,你才需要操作這個結構。
還有一個名字爲cLocks的成員變量。很明顯,它與時間沒有任何的關係–它是一個鎖的計數器。該參數是用來控制訪問數組數據的。在你訪問它之前,你必須鎖定數據。通過跟蹤該計數器,系統可以在不需要該數組時安全地刪除它。
創建SAFEARRAY
創建一個單維SAFEARRAY的簡單方法是通過使用SafeArrayCreateVector API函數。該函數可分配一個特定大小的連續內存塊。
SAFEARRAY *psa;
file:// create a safe array to store the stream data
file:// llen is the number of bytes in the array.
psa = SafeArrayCreateVector( VT_UI1, 0, llen );
SafeArrayCreateVector API創建一個SAFEARRAY,並且返回一個指向它的指針。首個參數用來定義數組的類型–它可以是任何有效的變量數據類型。爲了傳送一個串行化的對象,我們將使用最基本的類型–一個非負的字節數組。VT–UI1代表非負整形的變量類型,1個字節。
常數’0′定義數組的下界;在C++中,通常爲0。最後的參數llen定義數組元素的個數。在我們的例子中,這與我們將要傳送對象的字節數是一樣的。我們還沒有提數組大小(llen)是怎樣來的,這將在我們重新考查串行化時提及。
在你訪問SAFEARRAY數據之前,你必須調用SafeArrayAccessData。該函數鎖定數據並且返回一個指針。在這裏,鎖定數組意味着增加該數組的內部計數器(cLocks)。
file:// define a pointer to a byte array
unsigned char *pData = NULL;
SafeArrayAccessData( psa, (void**)&pData );
… use the safe array
SafeArrayUnaccessData(psa);
相應用來釋放數據的函數是SafeArrayUnaccessData(),該功能釋放該參數的計數。
類型 | 名字 | 描述 |
byte | VT_UI1 | 非負字節 |
short | VT_I2 | 有符號16位短整型 |
long | VT_I4 | 有符號32位長整型 |
float | VT_R4 | 一個IEEE 4字節實型數字 |
double | VT_R8 | 一個IEEE 8字節實型數字 |
VARIANT_BOOL | VT_BOOL | 16位布爾 0=false, 0xFFFF=true |
SCODE | VT_ERROR | 16位錯誤碼 |
CY | VT_CY | 16位貨幣結構 |
DATE | VT_DATE | 使用雙精度數字表示的日期 |
BSTR | VT_BSTR | visual basic風格的字符結構 |
DECIMAL | VT_DECIMAL | 一個十進制的結構 |
IUnknown | VT_UNKNOWN | 一個COM接口的指針 |
IDispatch | VT_DISPATCH | COM Dispatch接口的指針 |
SAFEARRAY | * VT_ARRAY | 一個用作傳送數組數據的特別結構 |
VARIANT | * VT_VARIANT | 一個VARIANT結構的指針 |
void | * | 普通的指針 |
VT_BYREF | 任何類型(除指針外)的指針 |