Use array parameters in COM - array pointer
Keywords: DCOM, array, custom type, Marshal, SafeArray, iCollection
1 use array pointers
An array pointer uses a standard C / C array representation. Each element in the array is sequentially discharged in memory in memory. The subscript of the array starts from 0. The address of the first element of the array (the element of the subscript is 0) is the pointer of the array. The memory space size of each element in the array must be fixed, only related to the array type. When calculating a pointer to an element in an array, the use of the byte number of the element multiplied by the elements can be obtained, and the offset between the elements and the array pointers can be obtained [1]. The address pointer of this element can be calculated based on this offset.
Using an array pointer is the most important thing to determine the array length, so that the serialization program can correctly copy memory. In order to generate a proxy and stubber program, we need to use Interface Definition Language (IDL) to describe interfaces and COM object types. MIDL reads the description in the IDL file, generates the code of TLB and proxy stub.
1.1 IDL declaration
1.1.1 Parameter Passing Direction
In order to improve sequential efficiency, the direction of delivery of parameters can be determined in the IDL. There are three passwords of the parameters: Input (IN), Output (OUT), and Input Output (IN, OUT). The input type parameter passes from the caller to the caller, and the called by the caller does not pass the invigorator. The output type parameters are opposite, from the called call from the caller, but the caller does not care about the initial value of the parameters. The input output type parameter passes to the caller when the call is called, and the caller can modify the parameters. This modification will copy the callback when calling returns.
Non-pointer types must be input type parameters. Output type parameters and input and output type parameters must be a pointer type.
1.1.2 Array length and replication length
In the IDL declaration, the array length and replication length should be set correctly. Array lengths define the size_is or min_is, the Max_is property, and the replication length is defined using length_is or first_is, the last_is property. In the current IDL implementation, Min_is is not implemented, so MIN_IS can only be 0.
The SIZE_IS property is used to set the length of the array in memory. Array in memory can also be defined by max_is and min_is. Their relationship is: size = max - min 1. Since min can only be 0, SIZE = MAX 1.
The Length_is property is used to set the number of elements that need to be copied in serialization. The number of elements that need to be copied can also be defined by first_is and last_is. Their relationship is: Length = last - first 1. First_is and length_is can be defined simultaneously to define the scope of the replication, or simultaneously define first_is and last_is to define the scope of the replication. If first_is is defined, Last_is and the valid max_is value are the same. If first_is is not defined, use the default value 0. However, Length_is and Last_is are not to be defined simultaneously. The range of replication elements cannot exceed the range of array itself. If no replication range is specified, the default replication range is the entire array.
The replication range is generally not used on a simple input parameter or output parameter, but only in the input and output type parameters [2]. The memory data specified in the IDL affects which memory is copied from the client to the COM side; when the COM side is returned, the data is copied back to the client program according to the replication range. The array can be different from the client replicates to the COM side and copying the client from the COM.
When array is used as an output parameter, there are two options: the caller establishes an array and the called party to establish an array. When the length of the output array is presented, the mode of the array should be established using the caller. When an array is used as an output, it needs to change in the attribute to OUT. See Example 2 and Example 3. The following is an example of using an array pointer.
Example 1: Calculate the sum of numbers in an array, and use the auxiliary variable to determine the data length that needs to be passed.
HRESULT SUM ([IN, SIZE_IS (count)] long * pnums,
Long count,
[OUT, RETVAL] Long * PRESULT);
You can also use the array style definition
HRESULT SUM
[in, size_is (count)] Long NumBers [],
Long count,
[OUT, RETVAL] Long * PRESULT);
Example 2: Calculate the square of the number of inner counts in the array, saving to the rear count element of the array, pay attention to the length and replication length of the array.
HRESULT SQUARE
[IN, OUT, SIZE_IS (Count * 2), Length_is (count)] long * parray,
Long count);
Or use the array style definition:
HRESULT SQUARE
[IN, OUT, SIZE_IS (Count * 2), Length_is (count)] long array [],
Long count);
Example 3: Number of previous N. Apply for memory by the caller. Only the definitions of the pointer style are listed here.
HRESULT Prime
Long N,
[OUT, SIZE_IS (N)] long * presult]);
1.1.3 Double pointer
In IDL, parameters for double or multiple pointer types can be used. Here is only the double pointers used in array outputs, and please refer to the relevant documentation about the use of multiple pointers.
Two length values separated by commas in double pointers, are the length of the top-level pointer array, respectively, and the length of the secondary pointer, respectively. Using the default value 1 in the case of a length value space. For example, the meaning of size_is (m, n) is that the top-level pointer length is M, and the secondary pointer length is n. SIZE_IS (, N) is equivalent to size_is (1, n).
When using an array pointer to transfer an array, it is common to use the double pointer of the top-level pointer. That is, pointing to the pointer of the array pointer.
1.1.4 Established array
If the array length of the output cannot be predicted, the function that needs to be called dynamically applies for memory and establish an array. At this time, because the calling party does not know the length of the array, it is impossible to apply for memory in advance. Therefore, it is necessary to apply for memory by the caller and pass the address of the application to the call. That is, the calling party will pass the address of the deposited group pointer address to the called party, that is, pass the parameters through the pointer of the array pointer.
Example 1: Number of employees, employee numbers are expressed, and the number of employees and each employee number is output parameters.
HRESULT GETSTAFFID
[OUT] long * pnumber,
[OUT, SIZE_IS (, * PNUMBER)] Long ** PRESULT]);
Example 2: Returns a pointer to the current number element in an array. The output is a pointer array, so the passing parameter is a triple pointer, but in nature is a two-pointer, so the size_is parameter still uses the dual pointer.
HRESULT prime2
Long N,
[IN, SIZE_IS (N)] long * pnums,
[OUT, SIZE_IS (, * PCOUNT)] long *** pprimenums,
[OUT] long * pcount);
1.1.5 multi-dimensional array
In the IDL, no multi-dimensional array is defined. If you want to use a multi-dimensional array, you must be converted into a one-dimensional number of groups. The length of the one-dimensional array is the product of each dimension length in the multi-dimensional array. For example, the array of 3 * 5 can be represented by an array of length 15.
Example 1: Calculate the value of the line.
HRESULT DETERMINANT
Long ORDER,
[in, size_is (order * order)] double * pnumbers,
[OUT] Double * PRESULT);
Use the type conversion to convert the multidimensional array to a one-dimensional array.
Double Num [10] [10];
Double Result;
// set the item in Array Num
HRESULT HR = Obj-> Determinant (10, (Double *) Num, & Result
Example 2: Calculate the inverse matrix, the output array is established by the caller.
HRESULT ANTIMAMATRIX
Long ORDER,
[in, size_is (Order * Order)] Double * Pmatrix,
[OUT, SIZE_IS (Order * Order)] Double * PANTIMATRIX);
Example 3: A conversion table (a two-dimensional array).
HRESULT GETCONVERTTABLE
[OUT] long * plinenum;
[out] long * pcolnum;
[OUT, SIZE_IS (, * PLINENUM * * PCOLNUM)] BOOL ** PTABLE;
In the output of Example 3, it is more complicated when the array element is obtained, and the elements of the row r column column column j column j column in the following line can be used:
IF (i <* plinenum && j <* pcolnum)
{
BPASS = (* PTABLE) [i * (* pcolnum) j];
}
1.1.6 string
A string is a special array form that does not define the length, but ends with a special flag-value 0. Since the strings are stored in the C language in a manner, this type is often used to deliver a string parameter. The element type of the string specified in the IDL can only be single byte or Wchar_t type, and cannot be multi-dimensional.
Defining the properties of strings are string. The string array can only be one-dimensional. If the string is an output parameter, you should use a double pointer or use the size_is property to specify the length of the buffer.
Example 1: String as input parameters
HRESULT PUTSTRING
[IN, STRING] Char * PSTR);
Example 2: String as an output parameter, is applied to memory.
HRESULT GETSTRING
[OUT, STRING] char ** PSTR);
Example 3: Output string, the caller applies for memory.
HRESULT GETSTRING2 (
[in] long nmaxsize,
[OUT, SIZE_IS (NMAXSIZE), STRING] CHAR * PSTR);
1.1.7 fixed length array
In the array pointer method mentioned above, the parameters in SIZE_IS can also be constant, but the efficiency is relatively low. If the array length is a constant, the definition of a fixed length array can be used. The array of fixed lengths can be multi-dimensional, which can be input, output, or input output type.
example 1:
HRESULT ADD2
Long Nums [10],
[OUT, RETVAL] Long * PRESULT);
Example 2:
HRESULT GETNUMBERS
[OUT] long Nums [10]);
1.2 Array Pointer Memory Management According to the COM specification, the input type parameter is applied and released by the caller. The output type parameter is applied for memory by the modified party, and the memory is released by the caller. The input and output type parameters are applied by the caller, and the caller can release and re-apply the memory, and finally release memory by the caller.
Since the agent and the stub are also involved in memory management due to the call and stub, the COM and clients must use the same memory management. In COM, the system provides a set of memory management functions. Any memory block involving the COM interface parameters must be managed through these functions. These function prototypes are listed. For details, please refer to the relevant documentation.
LPVOID COTASKMEMALLOC (Ulong CB);
Void CotaskMemFree (LPVOID PV);
LPVOID COTASKMEMREALLOC (LPVOID PV, ULONG CB);
[1] Accurately, the number of bytes of array elements account for the number of bytes of memory and the alignment parameters of compile time.
[2] The replication range also uses a large number of members in the custom type, which has exceeded the scope of this article, please refer to the relevant information.