|
|
/*++
Copyright (C) 1996-2001 Microsoft Corporation
Module Name:
SAFEARRY.CPP
Abstract:
CSafeArray implementation.
Notes: (1) Support only for arrays with origin at 0 or 1. Can VB deal with a SAFEARRAY of origin zero?
(2) Support only for the following OA types: VT_BSTR, VT_VARIANT, VT_UI1, VT_I2, VT_I4, VT_R8
History:
08-Apr-96 a-raymcc Created. 18-Mar-99 a-dcrews Added out-of-memory exception handling
--*/
#include "precomp.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <safearry.h>
#include <arrtempl.h>
#include <olewrap.h>
typedef struct { DWORD m_nMaxElementUsed; DWORD m_nFlags; DWORD m_nGrowBy; DWORD m_nStatus; DWORD m_nVarType; SAFEARRAYBOUND m_bound; } PersistHeaderBlock;
//***************************************************************************
//
// CSafeArray::CheckType
//
// Verifies that the constructor is being invoked with a supported type.
//
// PARAMETERS:
// nTest
// One of the supported OLE VT_ constants.
//
//***************************************************************************
void CSafeArray::CheckType(int nTest) { if (nTest != VT_BSTR && nTest != VT_VARIANT && nTest != VT_UI1 && nTest != VT_I2 && nTest != VT_I4 && nTest != VT_R4 && nTest != VT_R8 && nTest != VT_BOOL && nTest != VT_DISPATCH && nTest != VT_UNKNOWN ) Fatal("Caller attempted to use unsupported OLE Automation Type (VT_*)"); }
//***************************************************************************
//
// CSafeArray::CSafeArray
//
// Constructor which creates a new SAFEARRAY.
//
// PARAMETERS:
// vt
// An OLE VT_ type indicator, indicating the element type.
// nFlags
// The destruct policy, either <no_delete> or <auto_delete>. With
// <no_delete>, the underlying SAFEARRAY is not deallocated, whereas
// with <auto_delete> the destructor destroys the SAFEARRAY.
// nSize
// The initial size of the SAFEARRAY.
// nGrowBy
// The amount the SAFEARRAY should grow by when the user attempts to
// add elements to a full array.
//
//***************************************************************************
CSafeArray::CSafeArray( IN int vt, IN int nFlags, IN int nSize, IN int nGrowBy ) { CheckType(vt);
m_nMaxElementUsed = -1; m_nFlags = nFlags; m_nGrowBy = nGrowBy; m_nVarType = vt;
// Allocate the array.
// ===================
m_bound.cElements = nSize; m_bound.lLbound = 0;
m_pArray = COleAuto::_SafeArrayCreate((VARENUM) vt, 1, &m_bound);
if (m_pArray == 0) m_nStatus = failed; else m_nStatus = no_error;
m_nElementSize = SafeArrayGetElemsize( m_pArray ); }
//***************************************************************************
//
// CSafeArray::CSafeArray
//
// Constructor based on an existing SAFEARRAY.
//
// PARAMETERS:
// pSrc
// A pointer to an existing SAFEARRAY which is used as a source
// during object construction.
// nType
// One of the OLE VT_ type indicators.
// nFlags
// OR'ed Bit flags indicating the bind vs. copy, and the
// object destruct policy.
//
// The destruct policy is either <no_delete> or <auto_delete>. With
// <no_delete>, the underlying SAFEARRAY is not deallocated, whereas
// with <auto_delete> the destructor destroys the SAFEARRAY.
//
// Binding is indicated by <bind>, in which case the SAFEARRAY
// pointed to by <pSrc> becomes the internal SAFEARRAY of the
// object. Otherwise, this constructor makes a new copy of the
// SAFEARRAY for internal use.
// nGrowBy
// How much to grow the array by when it fills and the user attempts
// to add more elements. This allows the array to grow in chunks
// so that continuous Add() operations do not operate slowly on
// large arrays.
//
//***************************************************************************
CSafeArray::CSafeArray( IN SAFEARRAY *pSrcCopy, IN int nType, IN int nFlags, IN int nGrowBy ) { m_nStatus = no_error;
CheckType(nType);
// Verify that this is only a 1-dimensional array.
// ===============================================
if (1 != COleAuto::_SafeArrayGetDim(pSrcCopy)) m_nStatus = failed;
// Now copy the source or 'bind' the incoming array.
// ====================================================
if (nFlags & bind) m_pArray = pSrcCopy; else if (COleAuto::_SafeArrayCopy(pSrcCopy, &m_pArray) != S_OK) m_nStatus = failed;
// Get bound information.
// ======================
LONG uBound = 0; if (S_OK != COleAuto::_SafeArrayGetUBound(m_pArray, 1, &uBound)) m_nStatus = failed;
// Correct the Upper Bound into a size.
// ====================================
m_bound.cElements = uBound + 1; m_bound.lLbound = 0; m_nMaxElementUsed = uBound; m_nVarType = nType; m_nGrowBy = nGrowBy; m_nFlags = nFlags & 3; // Mask out the acquire & copy bits.
m_nElementSize = SafeArrayGetElemsize( m_pArray );
}
//***************************************************************************
//
// CSafeArray::GetScalarAt
//
// For class internal use. This function returns the element at
// the specified index.
//
// PARAMETERS:
// nIndex
// The index at which to retrieve the scalar.
//
// RETURN VALUE:
// The scalar at the specified the location.
//
//***************************************************************************
SA_ArrayScalar CSafeArray::GetScalarAt(IN int nIndex) { SA_ArrayScalar retval = {0};
// Check for out-of-range condition.
// =================================
if (nIndex > m_nMaxElementUsed + 1) return retval;
COleAuto::_SafeArrayGetElement(m_pArray, (long *) &nIndex, &retval); return retval; }
//***************************************************************************
//
// CSafeArray assignment operator.
//
//***************************************************************************
CSafeArray& CSafeArray::operator =(IN CSafeArray &Src) { Empty();
m_nMaxElementUsed = Src.m_nMaxElementUsed; m_nFlags = Src.m_nFlags; m_nGrowBy = Src.m_nGrowBy; m_nStatus = Src.m_nStatus; m_nVarType = Src.m_nVarType; m_bound = Src.m_bound; m_nElementSize = Src.m_nElementSize;
if (COleAuto::_SafeArrayCopy(Src.m_pArray, &m_pArray) != S_OK) m_nStatus = failed;
return *this; }
//***************************************************************************
//
// Copy constructor.
//
// This is implemented primarily via the assignment operator.
//
//***************************************************************************
CSafeArray::CSafeArray(CSafeArray &Src) { m_nMaxElementUsed = 0; m_nFlags = 0; m_nGrowBy = 0; m_nStatus = no_error; m_nVarType = VT_NULL; m_pArray = 0; m_bound.cElements = 0; m_bound.lLbound = 0;
*this = Src; }
//***************************************************************************
//
// CSafeArray::Add
//
// Adds the BSTR to the array, growing the array if required.
//
// PARAMETERS:
// Src
// The source BSTR to add to the array. If NULL, then a
// blank string is added by the underlying SAFEARRAY implementation.
// (there is no way to prevent this). This can point to
// an LPWSTR as well.
//
// RETURN VALUE:
// <no_error> or <failed>.
//
//***************************************************************************
int CSafeArray::AddBSTR(IN BSTR Src) { // If there is no more room in the array, then expand it.
// ======================================================
if (m_nMaxElementUsed == (int) m_bound.cElements - 1) {
if (m_nGrowBy == 0) return range_error;
m_bound.cElements += m_nGrowBy;
if (S_OK != COleAuto::_SafeArrayRedim(m_pArray, &m_bound)) m_nStatus = failed; }
m_nMaxElementUsed++;
BSTR Copy = COleAuto::_SysAllocString(Src); CSysFreeMe auto1(Copy);
if (COleAuto::_SafeArrayPutElement(m_pArray, (long *) &m_nMaxElementUsed, Copy) != S_OK) { m_nStatus = failed; return failed; }
return no_error; }
//***************************************************************************
//
// CSafeArray::AddVariant
//
// Adds the specified VARIANT to the array.
//
// PARAMETERS:
// pSrc
// A pointer to the source VARIANT, which is copied.
//
// RETURN VALUE:
// range_error, failed, no_error
//
//***************************************************************************
int CSafeArray::AddVariant(IN VARIANT *pSrc) { // If there is no more room in the array, then expand it.
// ======================================================
if (m_nMaxElementUsed == (int) m_bound.cElements - 1) {
if (m_nGrowBy == 0) return range_error; m_bound.cElements += m_nGrowBy;
if (S_OK != COleAuto::_SafeArrayRedim(m_pArray, &m_bound)) m_nStatus = failed; }
m_nMaxElementUsed++;
if (COleAuto::_SafeArrayPutElement(m_pArray, (long *) &m_nMaxElementUsed, pSrc) != S_OK) { m_nStatus = failed; return failed; }
return no_error; }
//***************************************************************************
//
// CSafeArray::AddDispatch
//
// Adds the specified IDispatch* to the array.
//
// PARAMETERS:
// pSrc
// A pointer to the source IDispatch*, which is AddRefed.
//
// RETURN VALUE:
// range_error, failed, no_error
//
//***************************************************************************
int CSafeArray::AddDispatch(IN IDispatch *pDisp) { // If there is no more room in the array, then expand it.
// ======================================================
if (m_nMaxElementUsed == (int) m_bound.cElements - 1) {
if (m_nGrowBy == 0) return range_error; m_bound.cElements += m_nGrowBy;
if (S_OK != COleAuto::_SafeArrayRedim(m_pArray, &m_bound)) m_nStatus = failed; }
m_nMaxElementUsed++;
if (COleAuto::_SafeArrayPutElement(m_pArray, (long *) &m_nMaxElementUsed, pDisp) != S_OK) { m_nStatus = failed; return failed; }
return no_error; }
//***************************************************************************
//
// CSafeArray::AddUnknown
//
// Adds the specified IUnknown* to the array.
//
// PARAMETERS:
// pSrc
// A pointer to the source IUnknown*, which is AddRefed.
//
// RETURN VALUE:
// range_error, failed, no_error
//
//***************************************************************************
int CSafeArray::AddUnknown(IN IUnknown *pUnk) { // If there is no more room in the array, then expand it.
// ======================================================
if (m_nMaxElementUsed == (int) m_bound.cElements - 1) {
if (m_nGrowBy == 0) return range_error; m_bound.cElements += m_nGrowBy;
if (S_OK != COleAuto::_SafeArrayRedim(m_pArray, &m_bound)) m_nStatus = failed; }
m_nMaxElementUsed++;
if (COleAuto::_SafeArrayPutElement(m_pArray, (long *) &m_nMaxElementUsed, pUnk) != S_OK) { m_nStatus = failed; return failed; }
return no_error; }
//***************************************************************************
//
// CSafeArray::GetBSTRAt
//
// If the array type is VT_BSTR, this returns the string at the specified
// index.
//
// PARAMETERS:
// nIndex
// The array index for which the string is requried.
//
// RETURN VALUE:
// A dynamically allocated BSTR which must be freed with SysFreeString.
// NULL is returned on error. If NULL was originally added at this
// location, a string with zero length will be returned, which still
// must be freed with SysFreeString.
//
//***************************************************************************
BSTR CSafeArray::GetBSTRAt(int nIndex) { BSTR StrPtr = 0;
if (nIndex >= (int) m_bound.cElements) return NULL;
if (S_OK != COleAuto::_SafeArrayGetElement(m_pArray, (long *) &nIndex, &StrPtr)) return NULL;
return StrPtr; }
BSTR CSafeArray::GetBSTRAtThrow(int nIndex) { BSTR StrPtr = 0;
if (nIndex >= (int) m_bound.cElements) throw CX_MemoryException();
if (S_OK != COleAuto::_SafeArrayGetElement(m_pArray, (long *) &nIndex, &StrPtr)) throw CX_MemoryException();
return StrPtr; }
//***************************************************************************
//
// CSafeArray::GetVariantAt
//
// PARAMETERS:
// nIndex
// The array index from which to retrieve the VARIANT.
//
// RETURN VALUE:
// Returns a new VARIANT at the specified location. The receiver must
// call VariantClear() on this VARIANT when it is no longer used.
//
//***************************************************************************
VARIANT CSafeArray::GetVariantAt(int nIndex) { VARIANT Var; COleAuto::_VariantInit(&Var);
if (nIndex >= (int) m_bound.cElements) return Var;
if (S_OK != COleAuto::_SafeArrayGetElement(m_pArray, (long *) &nIndex, &Var)) return Var;
return Var; }
//***************************************************************************
//
// CSafeArray::GetDispatchAt
//
// PARAMETERS:
// nIndex
// The array index from which to retrieve the IDispatch*.
//
// RETURN VALUE:
// Returns the IDispatch* at the specified location. The receiver must
// call Release on this pointer (if not NULL) when it is no longer used.
//
//***************************************************************************
IDispatch* CSafeArray::GetDispatchAt(int nIndex) { IDispatch* pDisp; if (nIndex >= (int) m_bound.cElements) return NULL;
if (S_OK != COleAuto::_SafeArrayGetElement(m_pArray, (long *) &nIndex, &pDisp)) return NULL;
return pDisp; }
//***************************************************************************
//
// CSafeArray::GetUnknownAt
//
// PARAMETERS:
// nIndex
// The array index from which to retrieve the IUnknown*.
//
// RETURN VALUE:
// Returns the IUnknown* at the specified location. The receiver must
// call Release on this pointer (if not NULL) when it is no longer used.
//
//***************************************************************************
IUnknown* CSafeArray::GetUnknownAt(int nIndex) { IUnknown* pUnk; if (nIndex >= (int) m_bound.cElements) return NULL;
if (S_OK != COleAuto::_SafeArrayGetElement(m_pArray, (long *) &nIndex, &pUnk)) return NULL;
return pUnk; }
//***************************************************************************
//
// CSafeArray::SetAt
//
// Replaces the BSTR value at the specified array index. The original
// BSTR value is automatically deallocated and replaced by the new value.
// You can only call this to replace an existing element or to add a
// new element to the end (one position past the last element). If the
// array size is 10, you can call this with 0..10, but not 11 or higher.
//
// PARAMETERS:
// nIndex
// The position at which to replace the element.
// Str
// The new string.
// nFlags
// If <acquire> this function acquires ownership of the string and
// can delete it. Otherwise, the caller retains ownership of the
// string.
//
// RETURN VALUE:
// no_error
// range_error
// failed
//
//***************************************************************************
int CSafeArray::SetBSTRAt( IN int nIndex, IN BSTR Str ) { // Check for out-of-range condition.
// =================================
if (nIndex > m_nMaxElementUsed + 1) return range_error;
// Check to see if we are adding a new element.
// ============================================
if (nIndex == m_nMaxElementUsed + 1) return AddBSTR(Str);
BSTR Copy = COleAuto::_SysAllocString(Str); CSysFreeMe auto1(Copy);
// If here, we are replacing an element.
// =====================================
if (COleAuto::_SafeArrayPutElement(m_pArray, (long *) &nIndex, Copy) != S_OK) { m_nStatus = failed; return failed; }
return no_error; }
//***************************************************************************
//
// CSafeArray::SetVariantAt
//
// Sets the VARIANT at the specified index.
//
// PARAMETERS:
// nIndex
// The index at which to set the VARIANT. The original contents
// at this location are automatically deallocated and replaced.
// pVal
// Used as the source of the new value. This is treated as read-only.
//
// RETURN VALUE:
// no_error, failed, range_error
//
//***************************************************************************
int CSafeArray::SetVariantAt( IN int nIndex, IN VARIANT *pVal ) { // Check for out-of-range condition.
// =================================
if (nIndex > m_nMaxElementUsed + 1) return range_error;
// Check to see if we are adding a new element.
// ============================================
if (nIndex == m_nMaxElementUsed + 1) return AddVariant(pVal);
// If here, we are replacing an element.
// =====================================
if (COleAuto::_SafeArrayPutElement(m_pArray, (long *) &nIndex, pVal) != S_OK) { m_nStatus = failed; return failed; }
return no_error; }
//***************************************************************************
//
// CSafeArray::SetDispatchAt
//
// Sets the IDispatch* at the specified index.
//
// PARAMETERS:
// nIndex
// The index at which to set the IDispatch*. The original contents
// at this location are automatically Released and replaced.
// pVal
// Used as the source of the new value. This is treated as read-only.
//
// RETURN VALUE:
// no_error, failed, range_error
//
//***************************************************************************
int CSafeArray::SetDispatchAt( IN int nIndex, IN IDispatch *pDisp ) { // Check for out-of-range condition.
// =================================
if (nIndex > m_nMaxElementUsed + 1) return range_error;
// Check to see if we are adding a new element.
// ============================================
if (nIndex == m_nMaxElementUsed + 1) return AddDispatch(pDisp);
// If here, we are replacing an element.
// =====================================
if (COleAuto::_SafeArrayPutElement(m_pArray, (long *) &nIndex, pDisp) != S_OK) { m_nStatus = failed; return failed; }
return no_error; }
//***************************************************************************
//
// CSafeArray::SetUnknownAt
//
// Sets the IUnknown* at the specified index.
//
// PARAMETERS:
// nIndex
// The index at which to set the IUnknown*. The original contents
// at this location are automatically Released and replaced.
// pVal
// Used as the source of the new value. This is treated as read-only.
//
// RETURN VALUE:
// no_error, failed, range_error
//
//***************************************************************************
int CSafeArray::SetUnknownAt( IN int nIndex, IN IUnknown *pUnk ) { // Check for out-of-range condition.
// =================================
if (nIndex > m_nMaxElementUsed + 1) return range_error;
// Check to see if we are adding a new element.
// ============================================
if (nIndex == m_nMaxElementUsed + 1) return AddUnknown(pUnk);
// If here, we are replacing an element.
// =====================================
if (COleAuto::_SafeArrayPutElement(m_pArray, (long *) &nIndex, pUnk) != S_OK) { m_nStatus = failed; return failed; }
return no_error; }
//***************************************************************************
//
// CSafeArray::RemoveAt
//
// Removes the element at the specified index. After a series of these
// operations, the caller should call the Trim() function.
//
// PARAMETERS:
// nIndex
// The target index for element removal.
//
// RETURN VALUE:
// no_error, range_error
//
//***************************************************************************
int CSafeArray::RemoveAt(IN int nIndex) { // Check for out-of-range condition.
// =================================
if (nIndex > m_nMaxElementUsed + 1) return range_error;
// Copy element n+1 into n.
// ========================
BSTR strVal; VARIANT v; SA_ArrayScalar scalar; IDispatch* pDisp; IUnknown* pUnk;
for (long i = nIndex; i < m_nMaxElementUsed; i++) { long nNext = i + 1;
if (m_nVarType == VT_BSTR) { COleAuto::_SafeArrayGetElement(m_pArray, &nNext, &strVal); COleAuto::_SafeArrayPutElement(m_pArray, &i, strVal); COleAuto::_SysFreeString(strVal); } else if (m_nVarType == VT_VARIANT) { COleAuto::_SafeArrayGetElement(m_pArray, &nNext, &v); COleAuto::_SafeArrayPutElement(m_pArray, &i, &v); COleAuto::_VariantClear(&v); } else if (m_nVarType == VT_DISPATCH) { COleAuto::_SafeArrayGetElement(m_pArray, &nNext, &pDisp); COleAuto::_SafeArrayPutElement(m_pArray, &i, pDisp); if(pDisp) pDisp->Release(); } else if (m_nVarType == VT_UNKNOWN) { COleAuto::_SafeArrayGetElement(m_pArray, &nNext, &pUnk); COleAuto::_SafeArrayPutElement(m_pArray, &i, pUnk); if(pUnk) pUnk->Release(); } else { COleAuto::_SafeArrayGetElement(m_pArray, &nNext, &scalar); COleAuto::_SafeArrayPutElement(m_pArray, &i, &scalar); } }
m_nMaxElementUsed--; return no_error; }
//***************************************************************************
//
// CSafeArray::SetScalarAt
//
// For class internal use. Sets the scalar type at the specified index.
//
// PARAMETERS:
// nIndex
// The target index.
// val
// The new value.
//
// RETURN VALUES:
// range_error, failed, no_error
//
//***************************************************************************
int CSafeArray::SetScalarAt(IN int nIndex, IN SA_ArrayScalar val) { // Check for out-of-range condition.
// =================================
if (nIndex > m_nMaxElementUsed + 1) return range_error;
// Check to see if we are adding a new element.
// ============================================
if (nIndex == m_nMaxElementUsed + 1) return AddScalar(val);
// If here, we are replacing an element.
// =====================================
if (COleAuto::_SafeArrayPutElement(m_pArray, (long *) &nIndex, &val) != S_OK) { m_nStatus = failed; return failed; }
return no_error; }
//***************************************************************************
//
// CSafeArray::AddScalar
//
// For class internal use only.
//
// Adds a new scalar to the 'end' of the array, growing it if required
// and if possible.
//
// PARAMETERS:
// val
// The new value.
//
// RETURN VALUE:
// no_error, range_error, failed
//
//***************************************************************************
int CSafeArray::AddScalar(IN SA_ArrayScalar val) { // If there is no more room in the array, then expand it.
// ======================================================
if (m_nMaxElementUsed == (int) m_bound.cElements - 1) {
if (m_nGrowBy == 0) return range_error;
m_bound.cElements += m_nGrowBy;
if (S_OK != COleAuto::_SafeArrayRedim(m_pArray, &m_bound)) m_nStatus = failed; }
m_nMaxElementUsed++;
if (COleAuto::_SafeArrayPutElement(m_pArray, (long *) &m_nMaxElementUsed, &val) != S_OK) { m_nStatus = failed; return failed; }
return no_error; }
//***************************************************************************
//
// CSafeArray::Empty
//
// Empties the SAFEARRAY.
//
//***************************************************************************
void CSafeArray::Empty() { m_nMaxElementUsed = 0; m_nFlags = 0; m_nGrowBy = 0; m_nStatus = no_error; m_nVarType = VT_NULL; if (m_pArray) COleAuto::_SafeArrayDestroy(m_pArray); m_pArray = 0; m_bound.cElements = 0; m_bound.lLbound = 0; m_nElementSize = 0L; }
//***************************************************************************
//
// CSafeArray::GetArrayCopy
//
// RETURN VALUE:
// A copy of the internal SAFEARRAY or NULL on error.
//
//***************************************************************************
SAFEARRAY *CSafeArray::GetArrayCopy() { SAFEARRAY *pCopy = 0; if (COleAuto::_SafeArrayCopy(m_pArray, &pCopy) != S_OK) return 0; return pCopy; }
//***************************************************************************
//
// CSafeArray destructor.
//
// If the internal flags are set to auto_delete, then the internal
// SAFEARRAY is destroyed during destruction.
//
//***************************************************************************
CSafeArray::~CSafeArray() { if (m_nFlags == auto_delete) COleAuto::_SafeArrayDestroy(m_pArray); }
//***************************************************************************
//
// CSafeArray::Trim
//
//***************************************************************************
int CSafeArray::Trim() { m_bound.cElements = m_nMaxElementUsed + 1;
// HACK for NT 3.51: may not redimention to size 0
// ===============================================
if(m_bound.cElements == 0) { COleAuto::_SafeArrayDestroy(m_pArray); m_pArray = COleAuto::_SafeArrayCreate((VARENUM) m_nVarType, 1, &m_bound); } else { COleAuto::_SafeArrayRedim(m_pArray, &m_bound); }
return no_error; }
//***************************************************************************
//
//***************************************************************************
void CSafeArray::Fatal(const char *pszMsg) { // MessageBox(0, pszMsg, "CSafeArray FATAL Error",
// MB_OK | MB_SYSTEMMODAL | MB_ICONEXCLAMATION);
}
int CSafeArray::GetActualVarType( VARTYPE* pvt ) { if ( FAILED( SafeArrayGetVartype( m_pArray, pvt ) ) ) return failed;
return no_error; }
int CSafeArray::SetRawData( void* pvSource, int nNumElements, int nElementSize ) { // If the number of elements we are setting is > than the number we are allocated
// for, or element size does not match we fail the operation
if ( nNumElements > m_bound.cElements || nElementSize != m_nElementSize ) { return failed; }
LPVOID pvDest = NULL;
HRESULT hr = Access( &pvDest );
if ( SUCCEEDED( hr ) ) { CopyMemory( pvDest, pvSource, nElementSize * nNumElements ); m_nMaxElementUsed = nNumElements - 1; Unaccess(); }
return ( SUCCEEDED( hr ) ? no_error : failed ); }
int CSafeArray::GetRawData( void* pvDest, int nBuffSize ) { // If the number of elements we will copy will exceed the destination
// buffer, don't do it!
if ( ( ( m_nMaxElementUsed + 1 ) * m_nElementSize ) > nBuffSize ) { return failed; } LPVOID pvSource = NULL;
HRESULT hr = Access( &pvSource );
if ( SUCCEEDED( hr ) ) { CopyMemory( pvDest, pvSource, ( m_nMaxElementUsed + 1) * m_nElementSize ); Unaccess(); }
return ( SUCCEEDED( hr ) ? no_error : failed ); }
|