Repository navigation
DSafeArray
Home › All Categories › sys/win › sys/win/com › DSafeArray
Holds a COM SAFEARRAY and destroys it, with all its elements, when it goes out of scope.
A SAFEARRAY is the array type of COM and Automation. Its descriptor records the element type
(a VARTYPE such as VT_BSTR, VT_I4 or VT_VARIANT), the number of dimensions, the number of
elements and lower bound of each dimension, a lock count and some flags. Arrays travel between
COM objects this way, usually inside a VARIANT whose type has the VT_ARRAY bit set.
DSafeArray holds one descriptor in its public field m_psa. The model to keep in mind:
- It owns the array. The destructor destroys the descriptor and every element: strings are freed, variants cleared and interface pointers released. Detach hands the array over to you; Attach takes one over.
-
Locked and unlocked arrays. An array made by a Constructor is unlocked.
One made by Create, CreateEx, CreateVector or
CreateVectorEx, and every copy (the copy constructor, Let,
CopyFrom, the constructors that take a
SAFEARRAY ptror aVARIANT ptr, and the arrays StrSplit and FileReadAllLinesA, FileReadAllLinesW return) and an attached one is kept locked. A locked array cannot change size: theAppend,Insert,DeleteandRemovemethods and the count-and-bound forms of Redim fail on it withDISP_E_ARRAYISLOCKED. To build a list that grows, create it with a constructor. LocksCount tells you which kind you have, andSafeArrayUnlock( *dsa )turns a locked one into an unlocked one. - Indexes include the lower bound. An array created with 5 elements and a lower bound of 1 has indexes 1 to 5. The two-dimensional overloads take the index in the first dimension, then the index in the second; elements are stored with the first index varying fastest.
-
Three kinds of element access. Methods ending in
Strwork onVT_BSTRarrays and methods ending inVaronVT_VARIANTarrays, and returnE_FAILfor any other type. The forms that take anany ptrcopy one element of ElemSize bytes to or from the address you give, asSafeArrayGetElementandSafeArrayPutElementdo: for aVT_BSTRarray the pointer given to a put is theBSTRitself, and a string got out is a copy you free. -
Results. Most methods return an
HRESULT:S_OK(0) on success.
#import "sys/win"
#import "sys/win/com"
using win, comBuilds a sorted list of names, fills an array of numbers through a pointer and copies it into a
VARIANT:
#import "sys/win"
#import "sys/win/com"
using win, com
' A list that grows: create it with a constructor, which leaves it unlocked
dim names as DSafeArray = DSafeArray( VT_BSTR, 0, 0 )
names.AppendStr( "Pear" )
names.AppendStr( "apple" )
names.AppendStr( "Fig" )
names.InsertStr( 0, "Banana" )
names.Sort()
print StrJoin( names, ", " ); " ("; names.Count; " items)"
print "fig is at index"; names.Find( "fig" )
' A fixed array of numbers, filled through a pointer to its data
dim squares as DSafeArray = DSafeArray( VT_I4, 5, 1 )
dim p as long ptr = squares.AccessData()
for i as long = 0 to squares.Count - 1
p[i] = ( i + 1 ) * ( i + 1 )
next
squares.UnaccessData()
dim n as long
squares.GetElement( 5, @n )
print "squares("; squares.LBound; " to"; squares.UBound; ") end with"; n
' Hand a copy to COM in a VARIANT
dim v as VARIANT
squares.CopyToVariant( @v )
print "vt = &h"; hex( v.vt )
VariantClear( @v )It prints (the sort is by character code, so capitals come first):
Banana, Fig, Pear, apple (4 items)
fig is at index 1
squares( 1 to 5) end with 25
vt = &h2003
| Member | Does |
|---|---|
| Constructor | Creates an empty DSafeArray, a new array, or a copy of another array. |
| Destructor | Destroys the array and its elements. |
| Let | Replaces the array with a copy of another. |
| GetPtr | Returns the SAFEARRAY descriptor. |
| Create | Creates the array of an empty DSafeArray. |
| CreateEx | Creates the array with an interface id or record description. |
| CreateVector | Creates a one-dimensional array in a single allocation. |
| CreateVectorEx | The same, with an interface id or record description. |
| NumDims | Returns the number of dimensions. |
| LBound, UBound | Return the lowest and highest index of a dimension. |
| Count | Returns the number of elements in a dimension. |
| ElemSize | Returns the size of one element in bytes. |
| IsResizable | Tells whether the array may change size. |
| GetType | Returns the VARTYPE of the elements. |
| LocksCount | Returns the lock count. |
| Flags, Features | Return the FADF_* flags. |
| AccessData | Locks the array and returns a pointer to its data. |
| UnaccessData | Releases the pointer from AccessData. |
| Redim | Changes the number of elements of the last dimension. |
| Copy | Returns a separate copy of the array. |
| CopyData | Copies the elements into another array of the same shape. |
| CopyFrom | Replaces the array with a copy of a SAFEARRAY. |
| PtrOfIndex | Returns the address of one element. |
| Destroy, Clear | Destroys the array. |
| DestroyData, Erase, Reset | Frees the elements and keeps the descriptor. |
| CopyFromVariant | Replaces the array with a copy of the one in a VARIANT. |
| MoveFromVariant | Copies the array out of a VARIANT and empties the VARIANT. |
| CopyToVariant | Puts a copy of the array in a VARIANT. |
| MoveToVariant | Moves the array into a VARIANT. |
| Attach | Takes over a SAFEARRAY. |
| Detach | Gives up the SAFEARRAY and returns it. |
| GetIID, SetIID | Read or set the interface id of an array of interfaces. |
| GetRecordInfo, SetRecordInfo | Read or set the record description of an array of records. |
| AppendElement, Append | Adds an element at the end. |
| AppendStr | Adds a string at the end of a VT_BSTR array. |
| AppendVar | Adds a DVARIANT at the end of a VT_VARIANT array. |
| InsertElement, Insert | Inserts an element. |
| InsertStr | Inserts a string into a VT_BSTR array. |
| InsertVar | Inserts a DVARIANT into a VT_VARIANT array. |
| DeleteElement, Remove | Removes an element of a numeric array. |
| DeleteStringElement, RemoveStr | Removes a string. |
| DeleteVariantElement, RemoveVar | Removes a variant. |
| FindElement, Find | Finds a string in a VT_BSTR array. |
| Sort | Sorts a VT_BSTR array. |
| GetElement, Get | Copies one element out. |
| GetStr | Returns one string of a VT_BSTR array. |
| GetVar | Returns one element of a VT_VARIANT array. |
| PutElement, Put | Stores one element. |
| PutStr | Stores one string in a VT_BSTR array. |
| PutVar | Stores one DVARIANT in a VT_VARIANT array. |
constructor
constructor( byval vt as VARTYPE, byval cDims as UINT, byval prgsabounds as SAFEARRAYBOUND ptr )
constructor( byval vt as VARTYPE, byval cElements as ulong = 0, byval lLBound as long = 0 )
constructor( byval vt as VARTYPE, byval cElements1 as ulong, byval lLBound1 as long, byval cElements2 as ulong, byval lLBound2 as long )
constructor( byref strType as string, byval cDims as UINT, byval prgsabounds as SAFEARRAYBOUND ptr )
constructor( byref strType as string, byval cElements as ulong = 0, byval lLBound as long = 0 )
constructor( byref strType as string, byval cElements1 as ulong, byval lLBound1 as long, byval cElements2 as ulong, byval lLBound2 as long )
constructor( byref dsa as DSafeArray )
constructor( byval psa as SAFEARRAY ptr )
constructor( byval psa as SAFEARRAY ptr, byval fAttach as boolean )
constructor( byval pvar as VARIANT ptr )- With no argument the
DSafeArrayis empty:m_psaisNULLuntil Create, Attach or an assignment gives it an array. - With a
VARTYPEand bounds it creates a new, unlocked array whose elements are all zero: numbers are 0, strings areNULLBSTRs (which COM reads as empty) and variants are empty. The one-dimensional form defaults to no elements and a lower bound of 0; the general form takescDimsbounds fromprgsabounds.VT_EMPTYandVT_NULLare not element types, and neitherVT_ARRAYnorVT_BYREFmay be added. - With a type name instead of a
VARTYPEit picks the type from the name, in any case:"STRING","BSTR"and"BSTRING"giveVT_BSTR;"BOOL","BOOLEAN"VT_BOOL;"BYTE"VT_I1;"UBYTE"VT_UI1;"SHORT"VT_I2;"USHORT"VT_UI2;"INT"VT_INT;"UINT"VT_UINT;"LONG"VT_I4;"ULONG"VT_UI4;"LONGINT"VT_I8;"ULONGINT"VT_UI8;"SINGLE","FLOAT"VT_R4;"DOUBLE"VT_R8;"VARIANT","DVARIANT"VT_VARIANT;"CY","CURRENCY"VT_CY;"DECIMAL"VT_DECIMAL;"UNKNOWN"VT_UNKNOWN;"DISPATCH"VT_DISPATCH;"FILETIME"VT_FILETIME;"DATE"VT_DATE;"USERDEFINED"VT_USERDEFINED;"PTR"VT_PTR. Any other name creates no array. - From another
DSafeArray, aSAFEARRAY ptror aVARIANT ptrholding an array it makes a copy, which is locked. WithfAttach=trueit takes overpsaitself instead of copying it: theDSafeArraythen destroys it.
| Parameter | Meaning |
|---|---|
vt |
The element type. |
strType |
The element type as a name. |
cDims, prgsabounds
|
The number of dimensions and an array of one SAFEARRAYBOUND (count, lower bound) per dimension. |
cElements, lLBound
|
The number of elements and the lowest index of a one-dimensional array. |
cElements1, lLBound1, cElements2, lLBound2
|
The same for the two dimensions of a two-dimensional array. |
dsa, psa, pvar
|
The array to copy. |
fAttach |
true to take over psa, false to copy it. |
Example
dim a as DSafeArray = DSafeArray( VT_BSTR, 3, 1 ) ' 3 strings, indexes 1 to 3
dim b as DSafeArray = DSafeArray( "DOUBLE", 4, 0, 2, 0 ) ' 4 x 2 doubles
print a.Count, b.NumDims ' 3 2Microsoft Learn: SafeArrayCreate
destructorUnlocks the array and destroys it with SafeArrayDestroy, freeing every string, clearing every
variant and releasing every interface pointer it holds. It unlocks once: an array that is still
locked after that (an array from Create or a copy, inside an
AccessData without its UnaccessData) is not destroyed.
Example
scope
dim a as DSafeArray = DSafeArray( VT_BSTR, 100, 0 )
end scope ' the array and its strings are freed hereMicrosoft Learn: SafeArrayDestroy
operator let( byref dsa as DSafeArray )
operator let( byval psa as SAFEARRAY ptr )
operator let( byval pvar as VARIANT ptr )Destroys the current array and replaces it with a copy of the one assigned: another
DSafeArray, a SAFEARRAY ptr, or the array inside a VARIANT (which must have VT_ARRAY in
its type). The copy is locked. The source is not changed.
Example
dim src as DSafeArray = DSafeArray( VT_I4, 4, 0 )
dim copy as DSafeArray
copy = src
print copy.Count, copy.LocksCount ' 4 1function GetPtr() as SAFEARRAY ptrReturns the SAFEARRAY descriptor, m_psa, to pass to a function that takes a
SAFEARRAY ptr. It still belongs to the DSafeArray: do not destroy it. *dsa returns the
same.
Returns the descriptor, or NULL for an empty DSafeArray.
Example
dim a as DSafeArray = DSafeArray( VT_I4, 4, 0 )
print SafeArrayGetDim( a.GetPtr() ) ' 1function Create( byval vt as VARTYPE, byval cDims as UINT, byval prgsabound as SAFEARRAYBOUND ptr ) as HRESULT
function Create( byval vt as VARTYPE, byval cElements as ulong, byval lLBound as long ) as HRESULT
function Create( byval vt as VARTYPE, byval cElements1 as ulong, byval lLBound1 as long, byval cElements2 as ulong, byval lLBound2 as long ) as HRESULTCreates the array of an empty DSafeArray, as the constructors do, and locks it, so it
cannot be resized with Append or the count-and-bound forms of Redim.
Returns S_OK; E_FAIL when the DSafeArray already holds an array; E_INVALIDARG for a
NULL bounds pointer or no dimensions; E_OUTOFMEMORY when the array could not be created.
Example
dim a as DSafeArray
if a.Create( VT_R8, 10, 0 ) = S_OK then print a.Count, a.LocksCount ' 10 1Microsoft Learn: SafeArrayCreate
function CreateEx( byval vt as VARTYPE, byval cDims as UINT, byval prgsabound as SAFEARRAYBOUND ptr, byval pvExtra as PVOID ) as HRESULT
function CreateEx( byval vt as VARTYPE, byval cElements as ulong, byval lLBound as long, byval pvExtra as any ptr ) as HRESULT
function CreateEx( byval vt as VARTYPE, byval cElements1 as ulong, byval lLBound1 as long, byval cElements2 as ulong, byval lLBound2 as long, byval pvExtra as any ptr ) as HRESULTLike Create, with pvExtra describing the elements: for VT_RECORD an IRecordInfo
pointer, for VT_UNKNOWN or VT_DISPATCH a pointer to the GUID of the interface every
element holds (the array then has FADF_HAVEIID and GetIID returns it). The
array is locked.
Returns as Create.
Example
dim a as DSafeArray
a.CreateEx( VT_UNKNOWN, 4, 0, cast( any ptr, @IID_IDispatch ) )Microsoft Learn: SafeArrayCreateEx
function CreateVector( byval vt as VARTYPE, byval cElements as ulong, byval lLBound as long ) as HRESULTCreates a one-dimensional array whose descriptor and data are one block of memory, and locks it.
It does not get FADF_FIXEDSIZE: the pointer form of Redim resizes it.
Returns S_OK; E_FAIL when the DSafeArray already holds an array; E_OUTOFMEMORY on
failure.
Example
dim a as DSafeArray
a.CreateVector( VT_I4, 3, 0 )Microsoft Learn: SafeArrayCreateVector
function CreateVectorEx( byval vt as VARTYPE, byval cElements as ulong, byval lLBound as long, byval pvExtra as any ptr ) as HRESULTCreateVector with pvExtra as in CreateEx. The array is locked.
Returns as CreateVector.
Example
dim a as DSafeArray
a.CreateVectorEx( VT_UNKNOWN, 2, 0, cast( any ptr, @IID_IUnknown ) )Microsoft Learn: SafeArrayCreateVectorEx
function NumDims() as UINTReturns the number of dimensions, or 0 for an empty DSafeArray.
Example
print DSafeArray( VT_I4, 3, 0, 2, 0 ).NumDims ' 2Microsoft Learn: SafeArrayGetDim
function LBound( byval nDim as UINT = 1 ) as long
function UBound( byval nDim as UINT = 1 ) as longReturn the lowest and the highest valid index of dimension nDim (1 is the first). Loop from
LBound to UBound to visit every element.
Returns the index, or 0 for an empty DSafeArray or a dimension that does not exist.
Example
dim a as DSafeArray = DSafeArray( VT_BSTR, 3, 1 )
for i as long = a.LBound to a.UBound
a.PutStr( i, BSTRING( "item" ) )
nextMicrosoft Learn: SafeArrayGetLBound
function Count( byval nDim as UINT = 1 ) as DWORDReturns the number of elements in dimension nDim, or 0 for an empty DSafeArray or a
dimension that does not exist.
Example
dim a as DSafeArray = DSafeArray( VT_I4, 3, 1, 2, 1 )
print a.Count( 1 ), a.Count( 2 ) ' 3 2function ElemSize() as UINTReturns the size of one element in bytes (8 for a BSTR, which is a pointer, 24 for a
VARIANT), or 0 for an empty DSafeArray. Pointed-to data is not counted.
Example
print DSafeArray( VT_R8, 1, 0 ).ElemSize ' 8Microsoft Learn: SafeArrayGetElemsize
function IsResizable() as booleanTells whether the array lacks the FADF_FIXEDSIZE flag. It does not look at the lock count, so
an array that is resizable in this sense may still refuse to grow while locked (see the
introduction).
Returns true when the array has no fixed size; false for a fixed-size or empty array.
Example
print DSafeArray( VT_I4, 2, 0 ).IsResizable ' truefunction GetType() as VARTYPEReturns the VARTYPE of the elements (VT_BSTR, VT_I4 …), or 0 for an empty
DSafeArray.
Example
if DSafeArray( "LONG", 2, 0 ).GetType = VT_I4 then print "an array of long"Microsoft Learn: SafeArrayGetVartype
function LocksCount() as UINTReturns how many times the array is locked without a matching unlock, read from the
descriptor: 0 for an array made by a constructor, 1 for one made by Create or copied, one more
while AccessData is in effect.
Example
dim a as DSafeArray = DSafeArray( VT_I4, 2, 0 )
print a.LocksCount ' 0function Flags() as ushort
function Features() as ushortBoth return the fFeatures field of the descriptor: FADF_* flags such as FADF_BSTR,
FADF_VARIANT, FADF_HAVEIID and FADF_FIXEDSIZE.
Returns the flags, or 0 for an empty DSafeArray.
Example
dim a as DSafeArray = DSafeArray( VT_BSTR, 1, 0 )
if a.Flags and FADF_BSTR then print "holds BSTRs"Microsoft Learn: SAFEARRAY structure
function AccessData() as any ptrLocks the array and returns a pointer to its first element, for fast reading and writing in a loop. The elements are stored one after the other, with the first index varying fastest. Call UnaccessData when done. Do not resize the array in between: the pointer form of Redim does not refuse, and the pointer may then no longer point at the data.
Returns the address of the data, or NULL.
Example
dim a as DSafeArray = DSafeArray( VT_I4, 3, 0 )
dim p as long ptr = a.AccessData()
p[0] = 10 : p[1] = 20 : p[2] = 30
a.UnaccessData()Microsoft Learn: SafeArrayAccessData
function UnaccessData() as HRESULTUndoes one AccessData: decrements the lock count and invalidates the pointer.
Returns S_OK, or E_UNEXPECTED when the array was not locked.
Example
dim a as DSafeArray = DSafeArray( VT_R8, 2, 0 )
dim p as double ptr = a.AccessData()
p[1] = 2.5
a.UnaccessData()Microsoft Learn: SafeArrayUnaccessData
function Redim( byval pnewsabounds as SAFEARRAYBOUND ptr ) as HRESULT
function Redim( byval cElements as DWORD, byval lLBound as long ) as HRESULT
function Redim( byval cElements1 as ulong, byval lLBound1 as long, byval cElements2 as ulong, byval lLBound2 as long ) as HRESULTChanges the bounds of the last dimension, the only one a SAFEARRAY can resize. Elements
in both the old and new bounds keep their values, new ones are zero or empty, and those that
fall outside are freed.
The forms differ in which arrays they accept:
- The pointer form temporarily unlocks the array, so it works on an array with one lock (made
by Create or copied). On an unlocked array, one made by a constructor, it fails with
E_UNEXPECTED. - The one-dimensional form, with a count and a lower bound, works on an unlocked array and
fails with
DISP_E_ARRAYISLOCKEDon a locked one. - The two-dimensional form applies
cElements1andlLBound1to the last dimension and ignorescElements2andlLBound2; like the one-dimensional form it needs an unlocked array.
Returns S_OK; E_FAIL for an empty or fixed-size array; DISP_E_ARRAYISLOCKED or
E_UNEXPECTED as above.
Example
dim a as DSafeArray = DSafeArray( VT_BSTR, 2, 0 )
a.Redim( 10, 0 ) ' now 10 strings, indexes 0 to 9Microsoft Learn: SafeArrayRedim
function Copy() as SAFEARRAY ptrMakes a complete, separate copy of the array, strings and all, and gives it to you: destroy it
with SafeArrayDestroy, or Attach it to another DSafeArray. The copy is unlocked.
Returns the new descriptor, or NULL for an empty DSafeArray or on failure.
Example
dim a as DSafeArray = DSafeArray( VT_I4, 3, 0 )
dim psa as SAFEARRAY ptr = a.Copy()
SafeArrayDestroy( psa )Microsoft Learn: SafeArrayCopy
function CopyData( byval psaTarget as SAFEARRAY ptr ) as HRESULTCopies every element into psaTarget, an existing array of the same type, dimensions and sizes,
after freeing what it held. The target is not allocated or resized.
Returns S_OK, or E_INVALIDARG when the arrays do not match.
Example
dim a as DSafeArray = DSafeArray( VT_I4, 3, 0 )
dim b as DSafeArray = DSafeArray( VT_I4, 3, 0 )
a.CopyData( b.GetPtr() )Microsoft Learn: SafeArrayCopyData
function CopyFrom( byval psaSrc as SAFEARRAY ptr ) as HRESULTDestroys the current array and replaces it with a locked copy of psaSrc. This is what the copy
constructor and Let call.
Returns the result of the copy: S_OK, or an error; E_INVALIDARG for a NULL source.
Example
dim a as DSafeArray = DSafeArray( VT_I4, 3, 0 )
dim b as DSafeArray
b.CopyFrom( a.GetPtr() )function PtrOfIndex( byval prgIndices as long ptr ) as any ptr
function PtrOfIndex( byval idx as long ) as any ptr
function PtrOfIndex( byval cElem as long, byval cDim as long ) as any ptrReturns the address of one element, without locking the array. For a multi-dimensional array pass an array of indexes, one per dimension, the first dimension first.
Returns the address, or NULL for an empty DSafeArray or a bad index.
Example
dim a as DSafeArray = DSafeArray( VT_I4, 3, 0 )
dim p as long ptr = a.PtrOfIndex( 2 )
*p = 99Microsoft Learn: SafeArrayPtrOfIndex
function Destroy() as HRESULT
function Clear() as HRESULTUnlock and destroy the array with all its elements, leaving the DSafeArray empty. Clear is
another name for Destroy.
It unlocks once before destroying, so an unlocked array inside AccessData is destroyed too, and the data pointer becomes invalid.
Returns S_OK (also for an empty DSafeArray), or DISP_E_ARRAYISLOCKED when the array is
still locked after that one unlock; it is then kept.
Example
dim a as DSafeArray = DSafeArray( VT_BSTR, 10, 0 )
a.Destroy()
print a.GetPtr() = NULL ' -1: truefunction DestroyData() as HRESULT
function Erase() as HRESULT
function Reset() as HRESULTUnlock the array and free all its elements, but keep the descriptor: the bounds are still
reported, the data is gone and puts fail with E_INVALIDARG. The three names do the same; to
start over, Destroy the array and create a new one.
Returns S_OK (also for an empty DSafeArray), or an error from SafeArrayDestroyData.
Example
dim a as DSafeArray = DSafeArray( VT_BSTR, 3, 0 )
a.DestroyData()Microsoft Learn: SafeArrayDestroyData
function CopyFromVariant( byval pvar as VARIANT ptr ) as HRESULTReplaces the array with a locked copy of the one in pvar. The VARIANT is not changed.
Returns S_OK; E_INVALIDARG for NULL; HRESULT_FROM_WIN32( ERROR_INVALID_DATA )
(&h8007000D) when the VARIANT does not hold an array.
Example
dim v as VARIANT
DSafeArray( VT_I4, 3, 0 ).CopyToVariant( @v )
dim a as DSafeArray
a.CopyFromVariant( @v )
VariantClear( @v )function MoveFromVariant( byval pvar as VARIANT ptr ) as HRESULTReplaces the array with a copy of the one in pvar and sets the VARIANT to VT_EMPTY. The
array the VARIANT held is not destroyed, and nothing refers to it any more: it leaks. Use
CopyFromVariant and then VariantClear, or Attach
pvar->parray and set pvar->vt to VT_EMPTY yourself, to take the array over.
Returns as CopyFromVariant.
Example
dim v as VARIANT
DSafeArray( VT_I4, 3, 0 ).CopyToVariant( @v )
dim a as DSafeArray
a.Attach( v.parray ) ' takes the array over without a copy
v.vt = VT_EMPTYfunction CopyToVariant( byval pvar as VARIANT ptr ) as HRESULTClears pvar and stores a copy of the array in it, with the element type plus VT_ARRAY as its
type (VT_ARRAY or VT_BSTR for an array of strings). Free it with VariantClear.
Returns S_OK; E_FAIL for an empty DSafeArray; E_INVALIDARG for NULL.
Example
dim a as DSafeArray = DSafeArray( VT_BSTR, 2, 0 )
dim v as VARIANT
a.CopyToVariant( @v )
VariantClear( @v )Microsoft Learn: SafeArrayCopy
function MoveToVariant( byval pvar as VARIANT ptr ) as HRESULTClears pvar, stores the array itself in it with the element type plus VT_ARRAY, and leaves
the DSafeArray empty. The array is unlocked first and now belongs to the VARIANT.
Returns the result of the unlock: S_OK for a locked array, but E_UNEXPECTED for one made
by a constructor, which was never locked; the move happens either way. E_FAIL for an empty
DSafeArray, E_INVALIDARG for NULL.
Example
dim a as DSafeArray = DSafeArray( VT_I4, 3, 0 )
dim v as VARIANT
a.MoveToVariant( @v )
VariantClear( @v )function Attach( byval psaSrc as SAFEARRAY ptr ) as HRESULTDestroys the current array and takes over psaSrc, locking it. The DSafeArray destroys it
later, so do not attach the same array to two of them or destroy it yourself.
Returns S_OK; E_FAIL for NULL; an error when the current array cannot be destroyed.
Example
dim psa as SAFEARRAY ptr = SafeArrayCreateVector( VT_I4, 0, 5 )
dim a as DSafeArray
a.Attach( psa )function Detach() as SAFEARRAY ptrUnlocks the array and gives it to you, leaving the DSafeArray empty. Destroy it with
SafeArrayDestroy when done.
Returns the descriptor, or NULL for an empty DSafeArray.
Example
dim a as DSafeArray = DSafeArray( VT_I4, 5, 0 )
dim psa as SAFEARRAY ptr = a.Detach()
SafeArrayDestroy( psa )function GetIID() as GUID
function SetIID( byval pguid as GUID ptr ) as HRESULTRead or set the GUID of the interface held by an array of VT_UNKNOWN or VT_DISPATCH
elements created with an interface id (CreateEx), which has FADF_HAVEIID set.
Returns GetIID: the GUID, or a null GUID when there is none. SetIID: S_OK; E_FAIL
for an empty DSafeArray; &h8007000D when the array has no FADF_HAVEIID.
Example
dim a as DSafeArray
a.CreateEx( VT_DISPATCH, 2, 0, cast( any ptr, @IID_IDispatch ) )
dim iid as GUID = a.GetIID()Microsoft Learn: SafeArrayGetIID
function GetRecordInfo() as IRecordInfo ptr
function SetRecordInfo( byval prinfo as IRecordInfo ptr ) as HRESULTRead or set the IRecordInfo that describes the structure held by an array of VT_RECORD
elements, which has FADF_RECORD set.
Returns GetRecordInfo: the interface, with a reference you release, or NULL when the
array has none. SetRecordInfo: S_OK; E_FAIL for an empty DSafeArray; &h8007000D when
the array has no FADF_RECORD.
Example
dim a as DSafeArray = DSafeArray( VT_I4, 2, 0 )
dim pri as IRecordInfo ptr = a.GetRecordInfo() ' NULL: not an array of recordsMicrosoft Learn: SafeArrayGetRecordInfo
function AppendElement( byval pData as any ptr ) as HRESULT
function AppendElement( byref bsData as BSTRING ) as HRESULT
function AppendElement( byref dvData as DVARIANT ) as HRESULT
function AppendElement( byval vData as VARIANT ) as HRESULT
function Append( byval pData as any ptr ) as HRESULT
function Append( byref bsData as BSTRING ) as HRESULT
function Append( byref dvData as DVARIANT ) as HRESULT
function Append( byval vData as VARIANT ) as HRESULTGrow a one-dimensional, unlocked array by one element and store the value there. The any ptr
form copies the data at pData like PutElement; the BSTRING form needs a
VT_BSTR array and the DVARIANT and VARIANT forms a VT_VARIANT array, and they store copies.
Returns S_OK; E_FAIL for an empty, multi-dimensional, fixed-size or wrongly typed array;
DISP_E_ARRAYISLOCKED for a locked one.
Example
dim a as DSafeArray = DSafeArray( VT_R8 )
dim x as double = 1.5
a.Append( @x )
print a.Count ' 1Microsoft Learn: SafeArrayRedim
function AppendStr( byval pwszData as wstring ptr ) as HRESULTGrows a one-dimensional, unlocked VT_BSTR array by one element holding a copy of pwszData.
Returns as AppendElement.
Example
dim a as DSafeArray = DSafeArray( VT_BSTR )
a.AppendStr( "first" )
a.AppendStr( "second" )function AppendVar( byref dvData as DVARIANT ) as HRESULTGrows a one-dimensional, unlocked VT_VARIANT array by one element holding a copy of dvData.
Returns as AppendElement.
Example
dim a as DSafeArray = DSafeArray( VT_VARIANT )
dim dv as DVARIANT = 123
a.AppendVar( dv )function InsertElement( byval nPos as long, byval pData as any ptr ) as HRESULT
function InsertElement( byval pData as any ptr ) as HRESULT
function InsertElement( byval nPos as long, byref bsData as BSTRING ) as HRESULT
function InsertElement( byref bsData as BSTRING ) as HRESULT
function InsertElement( byval nPos as long, byref dvData as DVARIANT ) as HRESULT
function InsertElement( byval nPos as long, byval vData as VARIANT ) as HRESULT
function InsertElement( byref dvData as DVARIANT ) as HRESULT
function InsertElement( byval vData as VARIANT ) as HRESULT
function Insert( byval nPos as long, byval pData as any ptr ) as HRESULT
function Insert( byval pData as any ptr ) as HRESULT
function Insert( byval nPos as long, byref bsData as BSTRING ) as HRESULT
function Insert( byref bsData as BSTRING ) as HRESULT
function Insert( byval nPos as long, byref dvData as DVARIANT ) as HRESULT
function Insert( byval nPos as long, byval vData as VARIANT ) as HRESULT
function Insert( byref dvData as DVARIANT ) as HRESULT
function Insert( byval vData as VARIANT ) as HRESULTInsert a value at index nPos, or at the lower bound when there is no nPos, moving the
elements from there on up by one. nPos must be an existing index; to add at the end use
Append. An empty array accepts its lower bound and the value is
appended. The array must be one-dimensional and unlocked.
- The
any ptrforms move the elements through an 8-byte buffer, so they suit arrays of numbers of up to 8 bytes; and they treat the element count as an index, which is only right for a lower bound of 0 or 1: with a higher lower bound an element is overwritten. - The
BSTRINGforms need aVT_BSTRarray, theDVARIANTandVARIANTforms aVT_VARIANTarray; they store copies.
Returns S_OK; DISP_E_BADINDEX for an index outside the bounds; E_FAIL or
DISP_E_ARRAYISLOCKED as for Append.
Example
dim a as DSafeArray = DSafeArray( VT_I4, 3, 0 )
dim v as long = 7
a.Insert( 0, @v ) ' 7 0 0 0function InsertStr( byval nPos as long, byval pwszData as wstring ptr ) as HRESULT
function InsertStr( byval pwszData as wstring ptr ) as HRESULTInserts a copy of pwszData at index nPos (or at the lower bound) of a one-dimensional,
unlocked VT_BSTR array, moving the later strings up. Any lower bound works.
Returns as InsertElement.
Example
dim a as DSafeArray = DSafeArray( VT_BSTR )
a.AppendStr( "b" )
a.InsertStr( 0, "a" ) ' a, bfunction InsertVar( byref dvData as DVARIANT ) as HRESULT
function InsertVar( byval nPos as long, byref dvData as DVARIANT ) as HRESULTInserts a copy of dvData at index nPos (or at the lower bound) of a one-dimensional, unlocked
VT_VARIANT array, moving the later elements up. Any lower bound works.
Returns as InsertElement.
Example
dim a as DSafeArray = DSafeArray( VT_VARIANT )
dim dv as DVARIANT = "text"
a.AppendVar( dv )
a.InsertVar( 0, dv )function DeleteElement( byval nPos as long ) as HRESULT
function Remove( byval nPos as long ) as HRESULTRemove the element at index nPos of a one-dimensional, unlocked array and shrink it by one. The
elements are moved through an 8-byte buffer, so these suit numbers of up to 8 bytes; for strings
and variants use RemoveStr and
RemoveVar. They treat the element count as an index, which is
only right for a lower bound of 0 or 1: with a higher lower bound the last element is removed
instead.
Returns S_OK; E_FAIL for an index outside the bounds or an unsuitable array;
DISP_E_ARRAYISLOCKED for a locked one.
Example
dim a as DSafeArray = DSafeArray( VT_I4, 3, 0 )
a.Remove( 1 )
print a.Count ' 2function DeleteStringElement( byval nPos as long ) as HRESULT
function RemoveStr( byval nPos as long ) as HRESULTRemove the string at index nPos of a one-dimensional, unlocked VT_BSTR array, freeing it, and
shrink the array by one. Any lower bound works.
Returns S_OK; E_FAIL for an index outside the bounds or an unsuitable array;
DISP_E_ARRAYISLOCKED for a locked one.
Example
dim a as DSafeArray = StrSplit( "a b c", " " )
SafeArrayUnlock( *a ) ' the result of StrSplit is locked
a.RemoveStr( 2 ) ' a, cfunction DeleteVariantElement( byval nPos as long ) as HRESULT
function RemoveVar( byval nPos as long ) as HRESULTRemove the variant at index nPos of a one-dimensional, unlocked VT_VARIANT array, clearing
it, and shrink the array by one. Any lower bound works.
Returns as RemoveStr.
Example
dim a as DSafeArray = DSafeArray( VT_VARIANT, 3, 0 )
a.RemoveVar( 0 )function FindElement( byref wszFind as wstring, byval IgnoreCase as boolean = true ) as long
function Find( byref wszFind as wstring, byval IgnoreCase as boolean = true ) as longSearch a one-dimensional VT_BSTR array for a string equal to wszFind, ignoring case unless
IgnoreCase is false.
Returns the index of the first match, or 0 when there is none or the array is not a
one-dimensional VT_BSTR array. In an array whose lower bound is 0 a match at the first index
also gives 0: compare the element when that matters.
Example
dim a as DSafeArray = StrSplit( "red green blue", " " )
print a.Find( "GREEN" ), a.Find( "GREEN", false ) ' 2 0function Sort( byval bAscend as boolean = true ) as HRESULTSorts a one-dimensional VT_BSTR array in place, ascending, or descending when bAscend is
false. Strings compare by character code, so capitals come before small letters. It works on
locked and unlocked arrays.
Returns S_OK; E_FAIL for an empty or unsuitable array.
Example
dim a as DSafeArray = StrSplit( "pear Fig apple", " " )
a.Sort()
print StrJoin( a, "," ) ' Fig,apple,pearfunction GetElement( byval prgIndices as long ptr, byval pData as any ptr ) as HRESULT
function GetElement( byval idx as long, byval pData as any ptr ) as HRESULT
function GetElement( byval cElem as long, byval cDim as long, byval pData as any ptr ) as HRESULT
function Get( byval prgIndices as long ptr, byval pData as any ptr ) as HRESULT
function Get( byval idx as long, byval pData as any ptr ) as HRESULT
function Get( byval cElem as long, byval cDim as long, byval pData as any ptr ) as HRESULT
function GetElement( byval prgIndices as long ptr, byref bsData as BSTRING ) as HRESULT
function GetElement( byval idx as long, byref bsData as BSTRING ) as HRESULT
function GetElement( byval cElem as long, byval cDim as long, byref bsData as BSTRING ) as HRESULT
function Get( byval prgIndices as long ptr, byref bsData as BSTRING ) as HRESULT
function Get( byval idx as long, byref bsData as BSTRING ) as HRESULT
function Get( byval cElem as long, byval cDim as long, byref bsData as BSTRING ) as HRESULT
function GetElement( byval prgIndices as long ptr, byref dvData as DVARIANT ) as HRESULT
function GetElement( byval idx as long, byref dvData as DVARIANT ) as HRESULT
function GetElement( byval cElem as long, byval cDim as long, byref dvData as DVARIANT ) as HRESULT
function Get( byval prgIndices as long ptr, byref dvData as DVARIANT ) as HRESULT
function Get( byval idx as long, byref dvData as DVARIANT ) as HRESULT
function Get( byval cElem as long, byval cDim as long, byref dvData as DVARIANT ) as HRESULTCopy the element at an index into your variable. A multi-dimensional array takes prgIndices,
an array of one index per dimension, the first dimension first; a two-dimensional one can take
the two indexes directly.
- The
any ptrforms copy ElemSize bytes topData: give the address of a variable of the element type. From aVT_BSTRarray you receive a newBSTRto free, from aVT_VARIANTarray a copy of theVARIANTto clear. - The
DVARIANTforms copy the element of aVT_VARIANTarray intodvData. - The
BSTRINGforms do not work as intended: they pass theBSTRING's text where the address of aBSTRis expected, so the copy of the element is written over the first characters ofbsData(or to address 0 whenbsDatais empty) and is never freed. Use GetStr.
Returns S_OK; DISP_E_BADINDEX for an index outside the bounds; E_FAIL for an empty or
wrongly typed array.
Example
dim a as DSafeArray = DSafeArray( "LONG", 3, 1, 2, 1 )
dim v as long = 32
a.PutElement( 3, 2, @v )
dim r as long
a.GetElement( 3, 2, @r ) ' r = 32Microsoft Learn: SafeArrayGetElement
function GetStr( byval prgIndices as long ptr ) as BSTRING
function GetStr( byval idx as long ) as BSTRING
function GetStr( byval cElem as long, byval cDim as long ) as BSTRINGReturns the string at an index of a VT_BSTR array as a BSTRING. Each call also allocates one
copy of the string that is not freed, so avoid it in long loops; reading through
AccessData costs nothing.
Returns the string, or an empty BSTRING for an empty or wrongly typed array.
Example
dim a as DSafeArray = StrSplit( "one two", " " )
dim u as ustring = a.GetStr( 2 )
print u ' twofunction GetVar( byval prgIndices as long ptr ) as DVARIANT
function GetVar( byval idx as long ) as DVARIANT
function GetVar( byval cElem as long, byval cDim as long ) as DVARIANTReturns the element at an index of a VT_VARIANT array as a DVARIANT.
Returns the value. For an empty or wrongly typed array the result is a DVARIANT holding the
number E_FAIL (VT_I4), not an empty one.
Example
dim a as DSafeArray = DSafeArray( VT_VARIANT )
dim dv as DVARIANT = 3.5
a.AppendVar( dv )
dim r as DVARIANT = a.GetVar( 0 )function PutElement( byval prgIndices as long ptr, byval pData as any ptr ) as HRESULT
function PutElement( byval idx as long, byval pData as any ptr ) as HRESULT
function PutElement( byval cElem as long, byval cDim as long, byval pData as any ptr ) as HRESULT
function Put( byval prgIndices as long ptr, byval pData as any ptr ) as HRESULT
function Put( byval idx as long, byval pData as any ptr ) as HRESULT
function Put( byval cElem as long, byval cDim as long, byval pData as any ptr ) as HRESULT
function PutElement( byval prgIndices as long ptr, byref bsData as BSTRING ) as HRESULT
function PutElement( byval idx as long, byref bsData as BSTRING ) as HRESULT
function PutElement( byval cElem as long, byval cDim as long, byref bsData as BSTRING ) as HRESULT
function PutElement( byval prgIndices as long ptr, byref dvData as DVARIANT ) as HRESULT
function PutElement( byval idx as long, byref dvData as DVARIANT ) as HRESULT
function PutElement( byval cElem as long, byval cDim as long, byref dvData as DVARIANT ) as HRESULTStore a value at an index, freeing the value it replaces. Indexes are given as in GetElement.
- The
any ptrforms copy the data atpData: the address of a number for a numeric array, theBSTRitself for aVT_BSTRarray, the address of aVARIANTfor aVT_VARIANTarray. Strings, variants and interfaces are copied orAddRefed. - The
BSTRINGforms need aVT_BSTRarray, theDVARIANTforms aVT_VARIANTarray.
Put has only the any ptr forms: with a BSTRING or a DVARIANT call PutElement,
PutStr or PutVar.
Returns S_OK; DISP_E_BADINDEX for an index outside the bounds; E_FAIL for an empty or
wrongly typed array.
Example
dim a as DSafeArray = DSafeArray( VT_BSTR, 2, 0 )
a.PutElement( 0, BSTRING( "zero" ) )
dim v as DSafeArray = DSafeArray( VT_I4, 2, 0 )
dim n as long = 5
v.Put( 1, @n )Microsoft Learn: SafeArrayPutElement
function PutStr( byval prgIndices as long ptr, byref bsData as BSTRING ) as HRESULT
function PutStr( byval idx as long, byref bsData as BSTRING ) as HRESULT
function PutStr( byval cElem as long, byval cDim as long, byref bsData as BSTRING ) as HRESULTStores a copy of bsData at an index of a VT_BSTR array, freeing the string it replaces.
Returns as PutElement.
Example
dim a as DSafeArray = DSafeArray( VT_BSTR, 2, 1 )
a.PutStr( 1, BSTRING( "one" ) )function PutVar( byval prgIndices as long ptr, byref dvData as DVARIANT ) as HRESULT
function PutVar( byval idx as long, byref dvData as DVARIANT ) as HRESULT
function PutVar( byval cElem as long, byval cDim as long, byref dvData as DVARIANT ) as HRESULTStores a copy of dvData at an index of a VT_VARIANT array, clearing the variant it replaces.
Returns as PutElement.
Example
dim a as DSafeArray = DSafeArray( VT_VARIANT, 2, 0 )
dim dv as DVARIANT = 42
a.PutVar( 0, dv )| Function | Does |
|---|---|
| Operator * (descriptor) | Returns the SAFEARRAY descriptor. |
| StrSplit | Splits a string into a VT_BSTR array. |
| StrJoin | Joins the strings of a VT_BSTR array. |
| FileReadAllLinesA, FileReadAllLinesW | Read the lines of a text file into a VT_BSTR array. |
| DSafeArrayCompare, DSafeArrayReverseCompare | Compare two BSTRs for qsort. |
operator *( byref dsa as DSafeArray ) as SAFEARRAY ptrReturns m_psa, like GetPtr.
Returns the descriptor, or NULL.
Example
dim a as DSafeArray = DSafeArray( VT_I4, 4, 0 )
print SafeArrayGetDim( *a ) ' 1function StrSplit( byref wszStr as wstring, byref wszDelimiters as wstring ) as DSafeArraySplits wszStr at every character that occurs in wszDelimiters and returns the pieces in a
VT_BSTR array with a lower bound of 1. Each delimiter is a single character; runs of delimiters
and delimiters at either end produce no empty pieces. The array is locked (see the introduction).
Returns the pieces; an array with no elements when there are none.
Example
dim a as DSafeArray = StrSplit( "- This, a sample string.", " ,.-" )
print a.Count; ": "; StrJoin( a, "|" ) ' 4: This|a|sample|stringfunction StrJoin( byref dsa as DSafeArray, byref wszDelimiter as wstring ) as ustringJoins the strings of a one-dimensional VT_BSTR array with wszDelimiter between them. When the
delimiter is the three characters "," (quote, comma, quote) every piece is also enclosed in
quotes, giving a line of quoted comma-separated fields. An empty delimiter joins the pieces
directly.
Returns the joined text, or an empty string for an array that is empty, multi-dimensional or
not VT_BSTR.
Example
dim a as DSafeArray = StrSplit( "a b c", " " )
print StrJoin( a, chr( 34, 44, 34 ) ) ' "a","b","c"function FileReadAllLinesA( byref wszFileName as wstring, byref szDelimiter as const zstring = chr( 13, 10 ) ) as DSafeArray
function FileReadAllLinesW( byref wszFileName as wstring, byref wszDelimiter as const wstring = chr( 13, 10 ) ) as DSafeArrayRead a text file and return its lines in a VT_BSTR array with a lower bound of 1.
FileReadAllLinesA reads an ANSI file (a UTF-8 byte-order mark is skipped, but the text is
converted from the ANSI code page); FileReadAllLinesW reads a UTF-16 file, skipping a
byte-order mark. The lines end at szDelimiter / wszDelimiter, CR LF by default.
Both have limits to know about:
- A line after the last delimiter is not returned, so end the file with a delimiter.
- A line no longer than the delimiter (2 characters with CR LF in
FileReadAllLinesA; 4 with CR LF inFileReadAllLinesW, which compares characters with bytes) comes back empty. - The file is read into a buffer with no terminating null, which the delimiter search can run past.
The array is locked (see the introduction). A file that cannot be opened gives an empty array.
Returns the lines.
Example
dim lines as DSafeArray = FileReadAllLinesA( "notes.txt" )
for i as long = lines.LBound to lines.UBound
print lines.GetStr( i ).Utf8
nextMicrosoft Learn: CreateFileW
function DSafeArrayCompare cdecl( byval a as BSTR ptr, byval b as BSTR ptr ) as long
function DSafeArrayReverseCompare cdecl( byval a as BSTR ptr, byval b as BSTR ptr ) as longThe comparison functions Sort passes to qsort: DSafeArrayCompare compares the two
strings by character code (wcscmp), DSafeArrayReverseCompare turns −1 into 1 and 1 into −1.
They take pointers to BSTRs, as qsort passes pointers to the elements.
Returns −1, 0 or 1.
Example
dim x as BSTR = SysAllocString( "apple" )
dim y as BSTR = SysAllocString( "banana" )
print DSafeArrayCompare( @x, @y ), DSafeArrayReverseCompare( @x, @y ) ' -1 1
SysFreeString( x ) : SysFreeString( y )- sys/win/com
- BSTRING and DVARIANT, the element types of string and variant arrays
-
CDispInvoke, whose methods return arrays inside a
DVARIANT - COM procedures
- Microsoft Learn: SAFEARRAY structure, SAFEARRAYBOUND structure
tiko-lang · Home · Feature Index · Keyword Index · License
FreeBASIC manual pages reproduced under the GNU FDL 1.3.
- Generics
- Interfaces
- For Each
- Iterators
- Tuples
- Array Results
- Defer
- Lambdas
- Block Strings
- Partial Types
- String Slices
- Embed
- Typed Variadics
- C Header Import
- Foreign Library Linking
- UString
- Fixed-Width Types
- Nullptr
- String Library
- Format
- Array
- Map
- Set
- LinkedList
- OrderedMap
- OrderedSet
- Sorting
- Optional
- Result
- Smart Pointers
- Date and Time (Chrono)
- Filesystem
- File Streams
- Config (INI and TOML)
- Codec
- Hash
- UUID
- OS
- Process
- Net
- HTTP and TLS
- Math Library
- Finance
- Logging
- Terminal TUI Library
- PsControls
- tkControls
- sys/win
- Goroutines and Channels
- LLVM Backend
- tiko build
- TIKO_COMPILER
- Variable Declarations
- Standard Data Types
- User Defined Types
- Procedures
- Operators
- Control Flow Statements
- Converting Data Types
- Array Functions
- String Functions
- Mathematical Functions
- Bit Manipulation
- Date and Time Functions
- File I/O Functions
- Console Functions
- User Input (Runtime Library)
- User Input Functions (Graphics Library)
- Screen Functions
- 2D Drawing Functions
- Graphics Library Reference
- Graphics Keyword List
- Memory Functions
- Threading Support Functions
- Error Handling Functions
- Operating System Functions
- Preprocessor
- Intrinsic Defines
- Miscellaneous Keywords
- Modularizing