在COM中使用陣列引數-SafeArray (轉)
在COM中使用陣列引數-SafeArray
關鍵字:DCOM、陣列、自定義型別、Marshal、SafeArray、ICollection
1 使用SafeArray
SafeArray是VB中的陣列方式。透過SafeArray,可以在VC++和VB間相互。SafeArray也是Automation中的標準陣列儲存方式。
1.1 SafeArray處理
COM提供了一套用於處理SafeArray。為了保證和SafeArray結構無關/editor/Editor.htm#_ftn1" name=_ftnref1>[1],程式中建立、讀取、更改和釋放SafeArray都應該透過這些API進行,而不應該直接讀寫SafeArray結構。
下面介紹常用的SafeArray處理函式。
1.1.1 建立SafeArray
SAFEARRAY* SafeArrayCreate(
VARTYPE vt,
unsigned int cDims,
SAFEARRRAYBOUND * rgsabound
);
:namespace prefix = o ns = "urn:schemas--com::office" />
SAFEARRAY SafeArrayCreateEx(
VARTYPE vt,
unsigned int cDims,
SAFEARRRAYBOUND * rgsabound
PVOID pvExtra
);
SAFEARRAY* SafeArrayCreateVector(
VARTYPE vt,
long lLbound,
unsigned int cElements
);
SAFEARRAY* SafeArrayCreateVectorEx(
VARTYPE vt,
long lLbound,
unsigned int cElements,
LPVOID pvExtra
);
SafeArrayCreate於建立多維普通陣列。SafeArrayCreateEx用於建立多維自定義型別或介面指標陣列。SafeArrayCreateVector用於建立一維普通陣列。SafeArrayCreateVectorEx用於建立一維自定義型別或介面指標陣列。
1.1.2 釋放陣列
HRESULT SafeArrayDestroy(
SAFEARRAY * psa
);
SafeArrayDestroy用於釋放建立的SafeArray陣列。
1.1.3 訪問資料
HRESULT SafeArrayAccessData(
SAFEARRAY * psa,
void HUGEP ** ppvData
);
HRESULT SafeArrayUnaccessData(
SAFEARRAY * psa
);
SafeArrayAccessData函式返回陣列的指標。而SafeArrayUnaccessData釋放透過SafeArrayAccessData所取得的指標。
1.2 SafeArray相關處理
1.2.1 建立SafeArray陣列
建立SafeArray可以使用COM提供的四個建立函式之一。所有的建立函式都返回一個SafeArray指標。透過這個指標可以讀寫SafeArray中的資料。SafeArray使用完後必須釋放。
1. SafeArrayCreateVector
SAFEARRAY* SafeArrayCreateVector(
VARTYPE vt,
long lLbound,
unsigned int cElements
);
這個函式用來建立簡單型別的一維陣列。這個函式有三個引數:vt是陣列型別、lLbound是陣列下界值(最小下標)和陣列長度。vt的取值如下表:
vt值
型別
VT_UI1
無符號1位元組整數(BYTE)陣列
VT_UI2
無符號2位元組整數()陣列
VT_UI4
無符號4位元組整數(DWORD)陣列
VT_UINT
無符號整數(UINT)陣列
VT_INT
有符號整數(INT)陣列
VT_I1
有符號1位元組整數陣列
VT_I2
有符號2位元組整數陣列
VT_I4
有符號4位元組整數陣列
VT_R4
IEEE 4位元組浮點數(float)陣列
VT_R8
IEEE 8位元組浮點數(double)陣列
VT_CY
8位元組定點數貨幣值陣列
VT_BSTR
VB字串陣列
VT_DECIMAL
12位元組定點數(大數字)陣列
VT_ERROR
標準錯誤編號陣列
VT_BOOL
布林值陣列
VT_DATE
日期型陣列
VT_VARIANT
Variant型別陣列
lLbound是陣列的最小下標,可以是取負數。cElements是陣列的長度。陣列的最大下標的值是最小下標加上陣列長度減一。
SafeArrayCreateVector函式返回SafeArray結構的指標。
2. SafeArrayCreateVectorEx
SAFEARRAY* SafeArrayCreateVectorEx(
VARTYPE vt,
long lLbound,
unsigned int cElements,
LPVOID pvExtra
);
這個函式用於建立自定義型別或COM的SafeArray陣列。和SafeArrayCreateVector類似,SafeArrayCreateVector也有型別、下界和長度的三個引數。SafeArrayCreateVectorEx還增加了一個引數pvExtra。
pvExtra的含義和vt的取值有關。當vt的取值在上表中的時候,pvExtra的取值沒有作用。當vt取值VT_RECORD時,SafeArrayCreateVectorEx返回一個自定義型別(結構structure或聯合union)的陣列。這時,pvExtra必須是一個指向IRecordInfo的指標。
當vt取值是VT_UNKNOWN或VT_DISPATCH時。pvExtra是一個指向IID(介面GUID)的指標。在目前的COM規範中,pvExtra只能是IID_IUnknown和IID_IDispatch。並且必須和vt的取值一致。
a. 建立自定義型別陣列
當vt是VT_RECORD時。pvExtra必須是一個IRecordInfo指標。絕大多數情況下,我們從TLB中取得自定義型別的IRecordInfo指標。以下是取得IRecordInfo的程式碼:
IRecordInfo * pRecordInfo;
hr = GetRecordInfoFromGuids(
LibID,
MajorVer,
MinorVer,
LOCALE_USER_DEFAULT,
TypeGUID,
&pRecordInfo);
上述程式碼中,LibID是所TLB的GUID,MajorVer和MinorVer分別是TLB的主、次版本號,TypeGUID是自定義結構的GUID。
函式返回的是IRecordInfo介面的指標。
b. 建立COM物件陣列
當需要建立COM陣列時,可以使用IUnknown指標,也可以用IDispatch指標。如果需要使用其它指標型別,應該使用QueryInterface方法取得,而不能直接在陣列中儲存。因為SafeArray陣列的序列化程式只能處理IUnknown和IDispatch兩種指標型別,如果在陣列中放其它介面型別的指標,可能在跨套間使用中會出現問題。
1.2.2 讀取和寫入SafeArray陣列。
讀寫SafeArray陣列時。應該使用COM提供的標準API。COM提供了大量函式用於SafeArray陣列的操作,本文中僅使用其中的兩個函式,SafeArrayAccessData和SafeArrayUnaccessData,和一些輔助用的函式。實際上是用這兩個函式就可以進行所有的陣列操作了。其它的函式用於對單個元素的操作,由於使用不多,而且也不高,所以本文中不進行說明。
1. SafeArrayAccessData
這個函式用於獲取SafeArray的資料指標,並鎖定SafeArray陣列的資料。在取得了資料指標之後,就可以直接訪問SafeArray陣列中的資料了。
如果陣列型別是Type,那麼所取得的資料指標實際上就是Type型別的陣列的地址。在多維陣列的情況下,必須把多個維度的下標轉換成一維下標進行訪問。
2. SafeArrayUnaccessData
這個函式的作用是對SafeArray資料解鎖,解鎖後,就不應該繼續對資料指標進行讀寫訪問。如果要訪問,必須重新獲取並鎖定資料。
3. 確定陣列結構
在訪問陣列之前,必須知道陣列中資料的型別,、維數以及每個維度的下界和長度。COM提供了取得這些陣列引數的函式。
取得型別,返回“VT_”開頭的型別列舉值:
HRESULT SafeArrayGetVartype (
SAFEARRAY * pSA,
VARTYPE * pVarType);
取得維數,返回陣列的維數:
UINT SafeArrayGetDim (
SAFEARRAY * pSA);
取得每個維度的屬性,返回指定維數(nDim)的上界和下界(nDim從1開始):
HRESULT SafeArrayGetLBound (
SAFEARRAY * pSA,
UINT nDim,
long * pLBound);
HRESULT SafeArrayGetUBound (
SAFEARRAY * pSA,
UINT nDim,
long * pUBound);
取得自定義型別介面,對於自定義結構陣列,返回自定義結構型別資料的指標:
HRESULT SafeArrayGetRecordInfo (
SAFEARRAY * pSA,
IRecordInfo ** ppRecordInfo);
4. 訪問普通一維陣列
從SafeArrayAccessData返回的指標實際上就是C語言中的一維陣列地址。在VC++中可以像訪問普通陣列一樣讀寫這個陣列。
需要注意的是,在C語言中,所有的陣列下標都是從0開始的。而在SafeArray中,陣列下標可以從任何數字開始。所以在訪問前必須進行轉換。轉換方法就是從SafeArray的下標中減去陣列的下界,就可以得到C語言中陣列的下標了。
如下:
Type * pData;
long LBound;
SafeArrayAccessData(pSA, (void HUGEP **) &pData);
SafeArrayGetLBound(pSA, 1, &LBound);
Type Item = pData[n – LBound];
5. 訪問多維陣列
訪問多維陣列和訪問一維陣列類似,只是要把多維下標轉換成一維下標。把多維下標轉換成一維下標的方法和在陣列指標中介紹的是相似的。
設:有n個維度,每個維度的長度(上界減去下界加一)分別是L1、L2、…、Ln。要轉換的下標是X1、X2、…、Xn。可以根據下述公式轉換成一維陣列的下標。
X1+X2*L1+X3*(L1*L2)+X4*(L1*L2*L3)+…+Xn*(L1*L2*…*L(n-1))
6. 訪問自定義結構陣列
訪問自定義結構陣列的時候,可以使用#iimport自動生成或者IDL編譯產生的型別定義。如果沒有辦法取得自定義結構的宣告,可以使用IRecordInfo介面中的方法間接訪問自定義結構。
首先需要取得自定義結構的長度,這可以透過IRecordInfo::GetSize方法取得。
訪問自定義結構中的欄位內容,透過IRecordInfo::GetField和IRecordInfo::PutField方法實現。
透過IRecordInfo中的其它方法還可以取得每個欄位的屬性內容。大家可以參考相關文件。
1.2.3 釋放SafeArray陣列
釋放SafeArray陣列應該透過COM的支援函式:
HRESULT SafeArrayDestroy(SAFEARRAY * pSA);
1.3 使用SafeArray的IDL定義
每個介面都要透過IDL生成和佔位程式程式碼。為了使代理和佔位程式能夠正確地對引數進行序列化,必須正確的書寫IDL定義。
MIDL工具直接支援SafeArray型別資料的傳遞。但是,在傳遞SafeArray資料的時候,必須透過SAFEARRAY的指標進行。困難在於,VC++ 6.0的新增方法和新增屬性的工具不能夠正確的處理SafeArray陣列的情況。
在IDL中,陣列必須指定型別,如下:
[id(10)] HRESULT Foo([in] SAFEARRAY(LONG) pParam);
在實現的函式宣告中,要使用相應的指標型別:
HRESULT Foo(SAFEARRAY * pParam);
輸出和輸入輸出型別的陣列引數,在IDL中必須使用指標引數,而在函式宣告中則是雙重指標。
[id(11)] HRESULT Foo2([out] SAFEARRAY(LONG) * ppParam);
函式宣告如下:
HRESULT Foo2(SAFEARRAY ** ppParam);
1.4 VARIANT和SafeArray
在VB的介面中,經常透過VARIANT傳遞陣列引數。這裡簡述一下使用VARIANT引數傳遞陣列中需要注意的地方。
1.4.1 輸入陣列
對於輸入陣列,可以使用VARIANT指標,也可以使用VARIANT型別引數。在這兩種情況下,VARIANT中的型別是不同的。
當使用VARIANT指標時,輸入的VARIANT引數的型別(vt引數的值)是VT_ARRAY | VT_BYREF | VT_xxx。此時,使用VARIANT引數的pparray欄位取得SafeArray指標。
如果引數是VARIANT,輸入的VARIANT引數的型別(vt引數的值)是VT_ARRAY | VT_xxx。使用VARIANT引數的parray欄位取得SafeArray指標。
必須注意這兩種情況下,VARIANT的型別不同,所以程式碼也會有區別。
1.4.2 輸出陣列
輸出和輸入輸出陣列,必須使用VARIANT指標,這時,VARIANT型別是VT_ARRYA | VT_BYREF | VT_xxx。
1.5 SafeArray管理
使用COM專用的建立和銷燬API函式處理SafeArray。
對於輸入型的SafeArray,呼叫方負責建立和銷燬SafeArray;對於輸出型的SafeArray,由被呼叫方建立,呼叫方銷燬;輸入輸出型SafeArray,呼叫方建立,被呼叫方可以銷燬並重新建立,最終由呼叫方銷燬。
這樣就可以在修改SafeArray結構時,保證程式相容性。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-998947/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 在COM中使用陣列引數-陣列指標 (轉)陣列指標
- 在COM中使用陣列引數-ICollection (轉)陣列
- 18SpringMvc_在業務控制方法中收集陣列引數SpringMVC陣列
- c# 方法引數_陣列引數C#陣列
- C#陣列引數C#陣列
- java 使用命令列引數(轉)Java命令列
- 在VB.Net中建立使用控制元件陣列 (轉)控制元件陣列
- toString 方法在陣列中的使用陣列
- 微信小程式中如何使用setData修改陣列或物件中的某一引數微信小程式陣列物件
- 在C++中實現變長陣列 (轉)C++陣列
- JavaScript進階系列02,函式作為引數以及在陣列中的應用JavaScript函式陣列
- 關於在類陣列中使用陣列方法陣列
- 將字串陣列轉換為浮點數陣列字串陣列
- js如何獲取指定元素在陣列中個數JS陣列
- [轉]Oracle陣列的使用Oracle陣列
- 給SQL Server傳送陣列引數的變通辦法(轉)SQLServer陣列
- imp commit引數的使用MIT
- Ghost命令列引數大全(轉)命令列
- c++ -- 二維陣列引數傳遞C++陣列
- Shell自學二(引數傳遞和陣列)陣列
- 每日一練(24):在排序陣列中查詢數字排序陣列
- javascript如何獲取指定元素在陣列中的數目JavaScript陣列
- 淺談二維陣列在傳參中的使用陣列
- 陣列-在Shell指令碼中的基本使用介紹陣列指令碼
- PowerShell中的陣列使用陣列
- 陣列中每個陣列元素出現的次數陣列
- Java中List陣列互轉Java陣列
- 在BCB中使用向量實現控制元件陣列 (轉)控制元件陣列
- typedef使用大全1(陣列) (轉)陣列
- iOS 字典轉陣列,陣列轉字典iOS陣列
- C++查詢一個數是否在陣列中find用法C++陣列
- 在陣列中尋找和為指定值的兩個數陣列
- 使用 XmlCommand 對Oracle傳引數XMLOracle
- 【陣列】1394. 找出陣列中的幸運數(簡單)陣列
- Java 陣列的不同定義方式和陣列長度為可變引數Java陣列
- 如何使用storcli在系統中管理RAID磁碟陣列AI陣列
- 陣列中重複的數字陣列
- Java 中的陣列 如何使用Java陣列