Fixed array

Array is passed as pointer reference in function parameters. C/C++/VB and other languages uses the same design. Array is passed as pointer in COM/DCOM also. However the size of the array always matters because in DCOM the client and server are not in same process address space. Thus the the size is required for marshalling process in stub proxy design so that it can copy the size of data in LPC or RPC transport buffer. We have seen size_is operator is used to inform the payload size of a fixed array. So this type of parameter passing always requires a secong argument which will contain the element count of an array. SAFEARRAY datastructure can eliminate this limitaion.

SAFEARRAY

SAFEARRAY is a data-structure used in COM/DCOM to hold additional metadata header of the array along with the payload buffer. SAFEARRAY is generic structure to hold the payload of the array and the element count, dimensions and data type of the elements. DCOM marcelling prosess can calculate the size of payload [= sizeof(data type of the elements) * element count * dimensions] VARIANT type is used in parameter type VARIANT and type of VARIANT as VT_ARRAY. marcelling prosess can easily calculate the payload size of the array and that is copied to LPC or RPC buffer. This SAFEARRAY structure holds the element count paramater inside it so there is no need of an extra parameter in function to tell the element count.

typedef struct tagSAFEARRAY {
  USHORT         cDims;
  USHORT         fFeatures;
  ULONG          cbElements;
  ULONG          cLocks;
  PVOID          pvData;
  SAFEARRAYBOUND rgsabound[1];
} SAFEARRAY, *LPSAFEARRAY;

SAFEARRAY Members

cDims The number of dimensions.

fFeatures - Flags.

  • FADF_AUTO 0x0001 An array that is allocated on the stack.
  • FADF_STATIC 0x0002 An array that is statically allocated.
  • FADF_EMBEDDED 0x0004 An array that is embedded in a structure.
  • FADF_FIXEDSIZE 0x0010 An array that may not be resized or reallocated.
  • FADF_RECORD 0x0020 An array that contains records. When set, there will be a pointer to the IRecordInfo interface at negative offset 4 in the array descriptor.
  • FADF_HAVEIID 0x0040 An array that has an IID identifying interface. When set, there will be a GUID at negative offset 16 in the safe array descriptor. Flag is set only when FADF_DISPATCH or FADF_UNKNOWN is also set.
  • FADF_HAVEVARTYPE 0x0080 An array that has a variant type. The variant type can be retrieved with SafeArrayGetVartype.
  • FADF_BSTR 0x0100 An array of BSTRs.
  • FADF_UNKNOWN 0x0200 An array of IUnknown*.
  • FADF_DISPATCH 0x0400 An array of IDispatch*.
  • FADF_VARIANT 0x0800 An array of VARIANTs.
  • FADF_RESERVED 0xF008 Bits reserved for future use.

cbElements The size of an array element.

cLocks The number of times the array has been locked without a corresponding unlock.

pvData The data.

rgsabound One bound for each dimension.

Remarks The array rgsabound is stored with the left-most dimension in rgsabound[0] and the right-most dimension in rgsabound[cDims - 1]. If an array was specified in a C-like syntax as a [2][5], it would have two elements in the rgsabound vector. Element 0 has an lLbound of 0 and a cElements of 2. Element 1 has an lLbound of 0 and a cElements of 5. The fFeatures flags describe attributes of an array that can affect how the array is released. The fFeatures field describes what type of data is stored in the SAFEARRAY and how the array is allocated. This allows freeing the array without referencing its containing variant. Thread Safety All public static members of the SAFEARRAY data type are thread safe. Instance members are not guaranteed to be thread safe. For example, consider an application that uses the SafeArrayLock and SafeArrayUnlock functions. If these functions are called concurrently from different threads on the same SAFEARRAY data type instance, an inconsistent lock count may be created. This will eventually cause the SafeArrayUnlock function to return E_UNEXPECTED. You can prevent this by providing your own synchronization code.

SAFEARRAYBOUND structure

Represents the bounds of one dimension of the array.

typedef struct tagSAFEARRAYBOUND {
  ULONG cElements;
  LONG  lLbound;
} SAFEARRAYBOUND, *LPSAFEARRAYBOUND;

cElements The number of elements in the dimension.

lLbound The lower bound of the dimension.

The arrays passed by IDispatch::Invoke within VARIANTARG are called safearrays. A safearray contains information about the number of dimensions and bounds within them. When an array is an argument or the return value of a function, the parray field of VARIANTARG points to an array descriptor. Do not access this array descriptor directly, unless you are creating arrays containing elements with nonvariant data types. Instead, use the functions SafeArrayAccessData and SafeArrayUnaccessData to access the data. The base type of the array is indicated by VT_ tag | VT_ARRAY. The data referenced by an array descriptor is stored in column-major order, which is the same ordering scheme used by Visual Basic and FORTRAN, but different from C and Pascal. Column-major order is when the left-most dimension (as specified in a programming language syntax) changes first.

Array Manipulation Functions

The following table contains the functions you use when accessing the data in the descriptor and the array.

FunctionDescription

SafeArrayAccessData

Increments the lock count of an array, and retrieves a pointer to the array data.

SafeArrayAddRef

Increases the pinning reference count of the descriptor for the specified safe array by one, and may increase the pinning reference count of the data for the specified safe array by one if that data was dynamically allocated, as determined by the descriptor of the safe array.

SafeArrayAllocData

Allocates memory for a safe array, based on a descriptor created with SafeArrayAllocDescriptor.

SafeArrayAllocDescriptor

Allocates memory for a safe array descriptor.

SafeArrayAllocDescriptorEx

Creates a safe array descriptor for an array of any valid variant type, including VT_RECORD, without allocating the array data.

SafeArrayCopy

Creates a copy of an existing safe array.

SafeArrayCopyData

Copies the source array to the specified target array after releasing any resources in the target array.

SafeArrayCreate

Creates a new array descriptor, allocates and initializes the data for the array, and returns a pointer to the new array descriptor.

SafeArrayCreateEx

Creates and returns a safe array descriptor from the specified VARTYPE, number of dimensions and bounds.

SafeArrayCreateVector

Creates a one-dimensional array. A safe array created withSafeArrayCreateVector is a fixed size, so the constant FADF_FIXEDSIZE is always set.

SafeArrayCreateVectorEx

Creates and returns a one-dimensional safe array of the specified VARTYPE and bounds.

SafeArrayDestroy

Destroys an existing array descriptor and all of the data in the array.

SafeArrayDestroyData

Destroys all the data in the specified safe array.

SafeArrayDestroyDescriptor

Destroys the descriptor of the specified safe array.

SafeArrayGetDim

Gets the number of dimensions in the array.

SafeArrayGetElement

Retrieves a single element of the array.

SafeArrayGetElemsize

Gets the size of an element.

SafeArrayGetIID

Gets the GUID of the interface contained within the specified safe array.

SafeArrayGetLBound

Gets the lower bound for any dimension of the specified safe array.

SafeArrayGetRecordInfo

IRecordInfo interface of the UDT contained in the specified safe array.

SafeArrayGetUBound

Gets the upper bound for any dimension of the specified safe array.

SafeArrayGetVartype

Gets the VARTYPE stored in the specified safe array.

SafeArrayLock

Increments the lock count of an array, and places a pointer to the array data in pvData of the array descriptor.

SafeArrayPtrOfIndex

Gets a pointer to an array element.

SafeArrayPutElement

Stores the data element at the specified location in the array.

SafeArrayRedim

Changes the right-most (least significant) bound of the specified safe array.

SafeArrayReleaseData

Decreases the pinning reference count for the specified safe array data by one. When that count reaches 0, the memory for that data is no longer prevented from being freed.

SafeArrayReleaseDescriptor

Decreases the pinning reference count for the descriptor of the specified safe array by one. When that count reaches 0, the memory for that descriptor is no longer prevented from being freed.

SafeArraySetIID

Sets the GUID of the interface for the specified safe array.

SafeArraySetRecordInfo

Sets the record info in the specified safe array.

SafeArrayUnaccessData

Decrements the lock count of an array, and invalidates the pointer retrieved by SafeArrayAccessData.

SafeArrayUnlock

Decrements the lock count of an array so it can be freed or resized.

SAFEARRAY VARIANT in IDL

[
  object,
  uuid(014EA17F-66F0-43A9-AC45-5796F0113291),
  dual,
  helpstring("IDaysArray Interface"),
  pointer_default(unique)
]
interface IDaysArray : IDispatch
{
  [id(1), helpstring("method GetDaysArray")]
  HRESULT GetDaysArray([out,retval] VARIANT *strDays);
};

SAFEARRAY VARIANT in COM server

STDMETHODIMP CDaysArray::GetDaysArray(VARIANT *strDays)
{
  SAFEARRAY FAR*  psarray;
  SAFEARRAYBOUND sabounds[1];
  BSTR strDay;  
  long nLbound;
  HRESULT hr;

  sabounds[0].lLbound=0;
  sabounds[0].cElements = 5;
  unsigned short *days[5] = 
  {
    L"Monday",
    L"Tuesday",
    L"Wednesday",
    L"Thursday",
    L"Friday"
  };
  psarray = SafeArrayCreate(VT_BSTR, 1, sabounds);
  if(psarray == NULL)
    return false;

  for(nLbound = 0; nLbound < (long)sabounds[0].cElements ; nLbound++)
  {
    strDay = SysAllocString(days[nLbound]);
    if(strDay == NULL)
      return false;
  
  hr = SafeArrayPutElement(psarray, &nLbound, strDay);
    if(FAILED(hr)){
        SafeArrayDestroy(psarray);
        return false;
    }
  }
  VariantInit(strDays);
  strDays->vt = VT_ARRAY|VT_BSTR;
  strDays->parray = psarray;
  SafeArrayUnaccessData(psarray);
  return S_OK;
}

SAFEARRAY VARIANT in COM Client

Option Explicit
Option Base 0
Dim DaysArray As DaysArray

Private Sub Form_Load()

  Dim varDays As Variant
  Dim day As Variant
  Dim str As String
  Dim i As Integer

  Set DaysArray = New CWEEKDAYSENUMXXXLib.DaysArray

  varDays = DaysArray.GetDaysArray
  str = "Week days are: " + vbCrLf
  For Each day In varDays
    str = str & day & "," & vbCrLf
  Next
  
  MsgBox str
  Set varDays = Nothing
  Set DaysArray = Nothing

End Sub

safearray vb client C++ server

About our authors: Team EQA

You have viewed 1 page out of 67. Your COM/DCOM learning is 0.00% complete. Login to check your learning progress.

#