Use array parameters in COM - SafeArray
Keywords: DCOM, array, custom type, Marshal, SafeArray, iCollection
1 use SafeArray
SafeArray is the array stored in VB. With SafeArray, you can call each other between VC and VBs. SafeArray is also a standard array storage method in Automation.
1.1 SafeArray handler
COM provides an API for processing SafeArray. To ensure that the program is not related to the SafeArray structure [1], the program is established, read, change, and release SafeArray should be performed by these APIs, and should not directly read and write the SafearRay structure.
The commonly used SafeArray handler is described below.
1.1.1 Establishing SafeArray
SafeArray * SafeArrayCreate
VARTYPE VT,
Unsigned int CDIMS,
Safearrraybound * Rgsabound
);
SafeArray SafearrayCreateex (
VARTYPE VT,
Unsigned int CDIMS,
Safearrraybound * Rgsabound
PVOID PVEXTRA
);
SafeArray * SafeArrayCreateVector (
VARTYPE VT,
Long Llbound,
Unsigned Int Celements
);
SafeArray * SafeArrayCreateVectorX (
VARTYPE VT,
Long Llbound,
Unsigned int Celements,
LPVOID PVEXTRA
);
SafeArrayCreate creates a multi-dimensional array. SafeArrayCreateEx is used to create a multi-dominant type or an interface pointer array. SafeArrayCreateVector is used to establish a Vitong array. SAFEARRAYCREATEVECTOREX is used to establish a custom-defined type or an interface pointer array.
1.1.2 Release array
HRESULT SAFEARRAYDESTROY
SafeArray * PSA
);
SafeArrayDestroy is used to release the created SafeArray array.
1.1.3 Access Data
HRESULT SAFEARRAYACCESSDATA (
SafeArray * PSA,
Void hugep ** ppvdata
);
HRESULT SAFEARRAYUNACCESSDATA (
SafeArray * PSA
);
The SafearrayAccessData function returns a pointer of the array. SafeArrayunAccessData releases the pointer achieved by SafeaAccessData.
1.2 SAFEARRAY related processing
1.2.1 Creating a SafeArray array
Creating SafeArray can use one of the four creation functions provided by COM. All creation functions returns a SafeArray pointer. You can read the data in SafeArray through this pointer. After SafeArray is used, you must be released.
SafeArrayCreateVector
SafeArray * SafeArrayCreateVector (
VARTYPE VT,
Long Llbound,
Unsigned Int Celements
);
This function is used to create a simple type of one-dimensional array. This function has three parameters: VT is an array type, LLBound is an array lower bound value (minimum subscript) and an array length. The value of VT is as follows:
Vt value
Types of
Vt_ui1
No symbol 1 byte integer (byte) array
Vt_ui2
No symbol 2 byte integer (Word) array
Vt_ui4
No symbol 4 byte integer (DWORD) array
VT_UINT No Symbol Integer (UINT) array
VT_INT
Symbol integer (int) array
VT_i1
Have a sign 1 byte integer array
VT_i2
A number of symbols 2 bytes analog
VT_i4
Have a symbol 4 byte integer array
Vt_r4
IEEE 4 byte floating point (FLOAT) array
Vt_r8
IEEE 8 byte floating point (double) array
VT_cy
8-byte fixed point number currency value array
VT_BSTR
VB string array
VT_DECIMAL
12-byte fixed point (large number) array
VT_ERROR
Standard error number array
VT_BOOL
Boolean value
Vt_date
Date type array
Vt_variant
VB VARIANT type array
Llbound is the minimum subscript of the array, which can be a number of negative. CELEMENTS is the length of the array. The value of the maximum subscript of the array is the minimum smaller plus array length minus one.
The SafeArrayCreateVector function returns a pointer to the SafeArray structure.
2. SafeArrayCreateVectorX
SafeArray * SafeArrayCreateVectorX (
VARTYPE VT,
Long Llbound,
Unsigned int Celements,
LPVOID PVEXTRA
);
This function is used to create a custom type or a SafeArray array of COM objects. Similar to SafeArrayCreateVector, SafeArrayCreateVector also has three parameters of type, lower bound, and length. SafeArrayCreateVectorX also adds a parameter PVEXTRA.
The meaning of PVextra is related to the value of VT. When the value of VT is in the above table, the value of PVextra does not work. When VT value VT_Record, SafeArrayCreateVectorEx returns an array of custom types (structural structure or joint Union). At this time, PVextra must be a pointer to IRECORDInfo.
When the VT value is VT_UNKNOWN or VT_DISPATCH. PVextra is a pointer to the IID (Interface GUID). In the current COM specification, PVextra can only be IID_IUNKNOWN and IIDISPATCH. And must be consistent with the value of VT.
a. Creating a custom type array
When VT is VT_Record. PVextra must be an IRECORDInfo pointer. In most cases, we get a custom type IRecordInfo pointer from the TLB. The following is the code that gets IRecordinfo:
Irecordinfo * PRecordinfo;
HR = GetRecordinfofromGuids
LibID,
Majorver,
Minorver,
Locale_user_default,
Typeguid,
& precordInfo);
In the above code, libid is the GUID of the TLB, Majorver, and Minorver, respectively, the secondary version number, TypeGuid is a custom structure.
The function returns the pointer to the IRecordInfo interface.
b. Creating a COM object array
When you need to create a COM array, you can use the iUnknown pointer, or you can use the iDispatch pointer. If you need to use other pointer types, you should use the QueryInterface method to get it, and you cannot be saved directly in the array. Because the serialization program of the SafeArray array can only process two pointer types of IUNKNOWN and IDSPATCH, if other interface types of interface types are placed in arrays, there may be problems in spanning.
1.2.2 Read and write the SafeArray array.
Read and write the SafeArray array. The standard API provided by COM should be used. COM provides a large number of functions for the SafeArray array, which uses only two functions, SafearrayAccessData, and SafearrayunAccessData, and some auxiliary functions. In fact, all arrays can be performed with these two functions. Other functions are used to operate for a single element, which is not described herein, which is not described herein. SafearrayAccessData
This function is used to get the data pointer of SafeArray and lock the data of the SafeArray array. After obtaining the data pointer, you can directly access the data in the SafeArray array.
If the array type is Type, the obtained data pointer is actually the address of the array of Type types. In the case of a multi-dimensional array, multiple dimensions must be converted into a one-dimensional title.
2. SafeArrayunAccessData
The function of this function is to unlock the SafeArray data and unlock, and should not continue to read and write the data pointer. If you want to access, you must re-locked the data.
3. Determine the array structure
Before accessing arrays, you must know the type, dimension of data in array, dimension, and lower bounds and lengths of each dimension. COM provides a function of acquiring these array parameters.
The type of acquisition, returns the type enumeration value of "VT_":
HRESULT SAFEARRAYGETVARTYPE
SafeArray * PSA,
VARTYPE * PVARTYPE);
Take the dimension, return to the number of dimensions:
Uint SafeArraygetdim
SafeArray * PSA);
Take the properties of each dimension, return the upper and lower bounds of the specified dimension (NDIM) (NDIM starting from 1):
HRESULT SAFEARRAYGETLBOUND
SafeArray * PSA,
UINT NDIM,
Long * plbound;
HRESULT SAFEARRAYGETBOUBOUND
SafeArray * PSA,
UINT NDIM,
Long * Pubound;
Take a custom type interface, and return to custom structural type data for custom structural arrays:
HRESULT SAFEARRAYGETRECORDINFO
SafeArray * PSA,
IRecordinfo ** pprecordinfo;
4. Visit ordinary one-dimensional array
The pointer returned from SaFearrayAccessData is actually a one-dimensional array address in the C language. In VC , you can read this array like accessing a normal array.
It should be noted that in the C language, all array subscripts start from 0. In SafeArray, the array subscript can start from any number. So the conversion must be performed before access. The conversion method is to subtract the lower bound of the array from the subscript of the SafeArray, and you can get the subscript of the array in the C language.
as follows:
TYPE * PDATA;
Long lbound;
SafearrayAccessData (PSA, (Void Hugep **) & PDATA);
SafeArraygetlbound (PSA, 1, & lbound);
TYPE ITEM = PDATA [N - LBound];
5. Access multi-dimensional array
Access a multidimensional array and access a one-dimensional array, just convert the multi-dimensional submit into one-dimensional subscript. Conversion of multi-dimensional subtocons into a one-dimensional subscript and is similar in array pointers.
With N dimensions, the length of each dimension (upper minus lower boundary plus one) is L1, L2, ..., LN. The subscript to be converted is x1, x2, ..., xn. It can be converted to the subscript of the one-dimensional array according to the following formula. X1 X2 * L1 X3 * (L1 * L2) X4 * (L1 * L2 * L3) ... XN * (L1 * L2 * ... * L (N-1))
6. Access to customized structural arrays
When accessing a custom structural array, you can use #iImport to automatically generate or identify the type definition generated by the IDL. If there is no way to obtain a declaration of custom structures, you can use the method in the IRecordInfo interface to indirect access to customizers.
First, you need to obtain the length of the custom structure, which can be obtained by IRECORDInfo :: getSize method.
Access the field content in the custom structure, implement it through IrecordInfo :: GetField and IRecordInfo :: Putfield method.
Other methods in IRecordinfo can also get the properties of each field. You can refer to the relevant documentation.
1.2.3 Release SafeArray array
Release the SafeArray array should pass the Coming support function:
HRESULT SAFEARRAYDESTROY (SAFEARRAY * PSA);
1.3 Using SafeArray IDL Definition
Each interface must generate a proxy and placeholder code by IDL. In order to make the agent and placeholder program to sequence the parameters correctly, the IDL definition must be written correctly.
The MIDL tool directly supports the passage of SafeArray type data. However, when passing SafeArray data, it must be performed through the pointer of SafeArray. Difficulties are that the Tools for the addition of VC 6.0 and the tool for adding attributes cannot correctly process the SafeArray array.
In IDL, the array must specify the type as follows:
[ID (10)] HRESULT FOO ([In] SafeArray (long) pParam);
In the implementation of the function declaration, use the corresponding pointer type:
HRESULT FOO (SafeArray * PParam);
The array parameters of the output and input output types must use pointer parameters in the IDL, and the dual pointer is in the function declaration.
[ID (11)] HRESULT FOO2 ([OUT] SafeArray (long) * PPPARAM);
The function declaration is as follows:
HRESULT FOO2 (SafeArray ** PPParam);
1.4 Variant and SafeArray
In the VB interface, array parameters are often passed through Variant. Here, a brief description takes place to use the Variant parameter to pass the array.
1.4.1 Enter an array
For input arrays, you can use a Variant pointer or use a Variant type parameter. In both cases, the types in Variant are different.
When using a Variant pointer, the type of the input Variant parameter (VAT parameter value) is VT_Array | VT_BYREF | VT_XXX. At this point, the SafearRay pointer is obtained using the PPARRAY field of the Variant parameter.
If the parameter is Variant, the type of VARIANT parameter (the value of the VT parameter) is VT_ARRAY | VT_XXX. Get the SafeArray pointer using the Parray field of the Variant parameter.
Must pay attention to these two cases, the type of variant is different, so the code will also be different.
1.4.2 output array
Output and input and output arrays, you must use a Variant pointer, then the Variant type is VT_ARrya | VT_BYREF | VT_XXX. 1.5 SafeArray Memory Management
Use COM-specific creation and destroy the API function to process SafeArray.
For input type SafeArray, the caller is responsible for creating and destroying SafeArray; for output type SafeArray, created by the converter, the caller is destroyed; the input output SafeArray, the supporter creation, the caller can destroy and recreate, and finally The caller is destroyed.
[1] This will ensure program compatibility when Microsoft modifies the SafeArray structure.