/************************************************************************ * SafeArrayCopy (OLEAUT32.27) * * Make a duplicate of a SafeArray. * * PARAMS * psa [I] Source for copy * ppsaOut [O] Destination for new copy * * RETURNS * Success: S_OK. ppsaOut contains a copy of the array. * Failure: An HRESULT error code indicating the error. * * NOTES * See SafeArray. */ HRESULT WINAPI SafeArrayCopy(SAFEARRAY *psa, SAFEARRAY **ppsaOut) { HRESULT hRet; TRACE("(%p,%p)\n", psa, ppsaOut); if (!ppsaOut) return E_INVALIDARG; *ppsaOut = NULL; if (!psa) return S_OK; /* Handles copying of NULL arrays */ if (!psa->cbElements) return E_INVALIDARG; if (psa->fFeatures & (FADF_RECORD|FADF_HAVEIID|FADF_HAVEVARTYPE)) { VARTYPE vt; hRet = SafeArrayGetVartype(psa, &vt); if (SUCCEEDED(hRet)) hRet = SafeArrayAllocDescriptorEx(vt, psa->cDims, ppsaOut); } else { hRet = SafeArrayAllocDescriptor(psa->cDims, ppsaOut); if (SUCCEEDED(hRet)) { (*ppsaOut)->fFeatures = psa->fFeatures & ~ignored_copy_features; (*ppsaOut)->cbElements = psa->cbElements; } } if (SUCCEEDED(hRet)) { /* Copy dimension bounds */ memcpy((*ppsaOut)->rgsabound, psa->rgsabound, psa->cDims * sizeof(SAFEARRAYBOUND)); (*ppsaOut)->pvData = SAFEARRAY_Malloc(SAFEARRAY_GetCellCount(psa) * psa->cbElements); if (!(*ppsaOut)->pvData) { SafeArrayDestroyDescriptor(*ppsaOut); *ppsaOut = NULL; return E_OUTOFMEMORY; } hRet = SAFEARRAY_CopyData(psa, *ppsaOut); if (FAILED(hRet)) { SAFEARRAY_Free((*ppsaOut)->pvData); SafeArrayDestroyDescriptor(*ppsaOut); *ppsaOut = NULL; return hRet; } } return hRet; }
/************************************************************************* * SafeArrayAllocData (OLEAUT32.37) * * Allocate the data area of a SafeArray. * * PARAMS * psa [I] SafeArray to allocate the data area of. * * RETURNS * Success: S_OK. The data area is allocated and initialised. * Failure: An HRESULT error code indicating the error. * * NOTES * See SafeArray. */ HRESULT WINAPI SafeArrayAllocData(SAFEARRAY *psa) { HRESULT hRet = E_INVALIDARG; TRACE("(%p)\n", psa); if (psa) { ULONG ulSize = SAFEARRAY_GetCellCount(psa); psa->pvData = SAFEARRAY_Malloc(ulSize * psa->cbElements); if (psa->pvData) { hRet = S_OK; TRACE("%u bytes allocated for data at %p (%u objects).\n", ulSize * psa->cbElements, psa->pvData, ulSize); } else hRet = E_OUTOFMEMORY; } return hRet; }
/************************************************************************ * SafeArrayDestroyData (OLEAUT32.39) * * Destroy the data associated with a SafeArray. * * PARAMS * psa [I] Array to delete the data from * * RETURNS * Success: S_OK. All items and the item data are freed. * Failure: An HRESULT error code indicating the error. * * NOTES * See SafeArray. */ HRESULT WINAPI SafeArrayDestroyData(SAFEARRAY *psa) { HRESULT hr; TRACE("(%p)\n", psa); if (!psa) return E_INVALIDARG; if (psa->cLocks) return DISP_E_ARRAYISLOCKED; /* Can't delete a locked array */ /* Delete the actual item data */ hr = SAFEARRAY_DestroyData(psa, 0); if (FAILED(hr)) return hr; if (psa->pvData) { if (psa->fFeatures & FADF_STATIC) { ZeroMemory(psa->pvData, SAFEARRAY_GetCellCount(psa) * psa->cbElements); return S_OK; } /* If this is not a vector, free the data memory block */ if (!(psa->fFeatures & FADF_CREATEVECTOR)) { if (!SAFEARRAY_Free(psa->pvData)) return E_UNEXPECTED; psa->pvData = NULL; } else psa->fFeatures |= FADF_DATADELETED; /* Mark the data deleted */ } return S_OK; }
unsigned char * WINAPI LPSAFEARRAY_UserUnmarshal(unsigned long *pFlags, unsigned char *Buffer, LPSAFEARRAY *ppsa) { ULONG_PTR ptr; wireSAFEARRAY wiresa; ULONG cDims; HRESULT hr; SF_TYPE sftype; ULONG cell_count; GUID guid; VARTYPE vt; SAFEARRAYBOUND *wiresab; TRACE("("); dump_user_flags(pFlags); TRACE(", %p, %p\n", Buffer, ppsa); ALIGN_POINTER(Buffer, 3); ptr = *(ULONG_PTR *)Buffer; Buffer += sizeof(ULONG_PTR); if (!ptr) { *ppsa = NULL; TRACE("NULL safe array unmarshaled\n"); return Buffer; } cDims = *(ULONG *)Buffer; Buffer += sizeof(ULONG); wiresa = (wireSAFEARRAY)Buffer; Buffer += FIELD_OFFSET(struct _wireSAFEARRAY, uArrayStructs); if (cDims != wiresa->cDims) RpcRaiseException(RPC_S_INVALID_BOUND); /* FIXME: there should be a limit on how large cDims can be */ vt = HIWORD(wiresa->cLocks); sftype = *(ULONG *)Buffer; Buffer += sizeof(ULONG); cell_count = *(ULONG *)Buffer; Buffer += sizeof(ULONG); ptr = *(ULONG_PTR *)Buffer; Buffer += sizeof(ULONG_PTR); if (sftype == SF_HAVEIID) { memcpy(&guid, Buffer, sizeof(guid)); Buffer += sizeof(guid); } wiresab = (SAFEARRAYBOUND *)Buffer; Buffer += sizeof(wiresab[0]) * wiresa->cDims; *ppsa = SafeArrayCreateEx(vt, wiresa->cDims, wiresab, NULL); if (!*ppsa) RpcRaiseException(E_OUTOFMEMORY); /* be careful about which flags we set since they could be a security * risk */ (*ppsa)->fFeatures &= FADF_AUTOSETFLAGS; (*ppsa)->fFeatures |= (wiresa->fFeatures & ~(FADF_AUTOSETFLAGS)); /* FIXME: there should be a limit on how large wiresa->cbElements can be */ (*ppsa)->cbElements = wiresa->cbElements; (*ppsa)->cLocks = LOWORD(wiresa->cLocks); hr = SafeArrayAllocData(*ppsa); if (FAILED(hr)) RpcRaiseException(hr); if ((*(ULONG *)Buffer != cell_count) || (SAFEARRAY_GetCellCount(*ppsa) != cell_count)) RpcRaiseException(RPC_S_INVALID_BOUND); Buffer += sizeof(ULONG); if (ptr) { switch (sftype) { case SF_BSTR: { BSTR* lpBstr; for (lpBstr = (BSTR*)(*ppsa)->pvData; cell_count; cell_count--, lpBstr++) Buffer = BSTR_UserUnmarshal(pFlags, Buffer, lpBstr); break; } case SF_DISPATCH: case SF_UNKNOWN: case SF_HAVEIID: FIXME("marshal interfaces\n"); break; case SF_VARIANT: { VARIANT* lpVariant; for (lpVariant = (VARIANT*)(*ppsa)->pvData; cell_count; cell_count--, lpVariant++) Buffer = VARIANT_UserUnmarshal(pFlags, Buffer, lpVariant); break; } case SF_RECORD: { FIXME("set record info\n"); break; } case SF_I8: ALIGN_POINTER(Buffer, 7); /* fallthrough */ case SF_I1: case SF_I2: case SF_I4: /* Just copy the data over */ memcpy((*ppsa)->pvData, Buffer, cell_count * (*ppsa)->cbElements); Buffer += cell_count * (*ppsa)->cbElements; break; default: break; } } TRACE("safe array unmarshaled: %p\n", *ppsa); return Buffer; }
unsigned char * WINAPI LPSAFEARRAY_UserMarshal(unsigned long *pFlags, unsigned char *Buffer, LPSAFEARRAY *ppsa) { HRESULT hr; TRACE("("); dump_user_flags(pFlags); TRACE(", %p, &%p\n", Buffer, *ppsa); ALIGN_POINTER(Buffer, 3); *(ULONG_PTR *)Buffer = *ppsa ? TRUE : FALSE; Buffer += sizeof(ULONG_PTR); if (*ppsa) { VARTYPE vt; SAFEARRAY *psa = *ppsa; ULONG ulCellCount = SAFEARRAY_GetCellCount(psa); wireSAFEARRAY wiresa; SF_TYPE sftype; GUID guid; *(ULONG *)Buffer = psa->cDims; Buffer += sizeof(ULONG); wiresa = (wireSAFEARRAY)Buffer; wiresa->cDims = psa->cDims; wiresa->fFeatures = psa->fFeatures; wiresa->cbElements = psa->cbElements; hr = SafeArrayGetVartype(psa, &vt); if (FAILED(hr)) RpcRaiseException(hr); wiresa->cLocks = (USHORT)psa->cLocks | (vt << 16); Buffer += FIELD_OFFSET(struct _wireSAFEARRAY, uArrayStructs); sftype = SAFEARRAY_GetUnionType(psa); *(ULONG *)Buffer = sftype; Buffer += sizeof(ULONG); *(ULONG *)Buffer = ulCellCount; Buffer += sizeof(ULONG); *(ULONG_PTR *)Buffer = (ULONG_PTR)psa->pvData; Buffer += sizeof(ULONG_PTR); if (sftype == SF_HAVEIID) { SafeArrayGetIID(psa, &guid); memcpy(Buffer, &guid, sizeof(guid)); Buffer += sizeof(guid); } memcpy(Buffer, psa->rgsabound, sizeof(psa->rgsabound[0]) * psa->cDims); Buffer += sizeof(psa->rgsabound[0]) * psa->cDims; *(ULONG *)Buffer = ulCellCount; Buffer += sizeof(ULONG); if (psa->pvData) { switch (sftype) { case SF_BSTR: { BSTR* lpBstr; for (lpBstr = (BSTR*)psa->pvData; ulCellCount; ulCellCount--, lpBstr++) Buffer = BSTR_UserMarshal(pFlags, Buffer, lpBstr); break; } case SF_DISPATCH: case SF_UNKNOWN: case SF_HAVEIID: FIXME("marshal interfaces\n"); break; case SF_VARIANT: { VARIANT* lpVariant; for (lpVariant = (VARIANT*)psa->pvData; ulCellCount; ulCellCount--, lpVariant++) Buffer = VARIANT_UserMarshal(pFlags, Buffer, lpVariant); break; } case SF_RECORD: { IRecordInfo* pRecInfo = NULL; hr = SafeArrayGetRecordInfo(psa, &pRecInfo); if (FAILED(hr)) RpcRaiseException(hr); if (pRecInfo) { FIXME("write record info %p\n", pRecInfo); IRecordInfo_Release(pRecInfo); } break; } case SF_I8: ALIGN_POINTER(Buffer, 7); /* fallthrough */ case SF_I1: case SF_I2: case SF_I4: /* Just copy the data over */ memcpy(Buffer, psa->pvData, ulCellCount * psa->cbElements); Buffer += ulCellCount * psa->cbElements; break; default: break; } } } return Buffer; }
unsigned long WINAPI LPSAFEARRAY_UserSize(unsigned long *pFlags, unsigned long StartingSize, LPSAFEARRAY *ppsa) { unsigned long size = StartingSize; TRACE("("); dump_user_flags(pFlags); TRACE(", %ld, %p\n", StartingSize, *ppsa); ALIGN_LENGTH(size, 3); size += sizeof(ULONG_PTR); if (*ppsa) { SAFEARRAY *psa = *ppsa; ULONG ulCellCount = SAFEARRAY_GetCellCount(psa); SF_TYPE sftype; HRESULT hr; size += sizeof(ULONG); size += FIELD_OFFSET(struct _wireSAFEARRAY, uArrayStructs); sftype = SAFEARRAY_GetUnionType(psa); size += sizeof(ULONG); size += sizeof(ULONG); size += sizeof(ULONG_PTR); if (sftype == SF_HAVEIID) size += sizeof(IID); size += sizeof(psa->rgsabound[0]) * psa->cDims; size += sizeof(ULONG); switch (sftype) { case SF_BSTR: { BSTR* lpBstr; for (lpBstr = (BSTR*)psa->pvData; ulCellCount; ulCellCount--, lpBstr++) size = BSTR_UserSize(pFlags, size, lpBstr); break; } case SF_DISPATCH: case SF_UNKNOWN: case SF_HAVEIID: FIXME("size interfaces\n"); break; case SF_VARIANT: { VARIANT* lpVariant; for (lpVariant = (VARIANT*)psa->pvData; ulCellCount; ulCellCount--, lpVariant++) size = VARIANT_UserSize(pFlags, size, lpVariant); break; } case SF_RECORD: { IRecordInfo* pRecInfo = NULL; hr = SafeArrayGetRecordInfo(psa, &pRecInfo); if (FAILED(hr)) RpcRaiseException(hr); if (pRecInfo) { FIXME("size record info %p\n", pRecInfo); IRecordInfo_Release(pRecInfo); } break; } case SF_I8: ALIGN_LENGTH(size, 7); /* fallthrough */ case SF_I1: case SF_I2: case SF_I4: size += ulCellCount * psa->cbElements; break; default: break; } } return size; }
/* Copy data items from one array to another. Destination data is freed before copy. */ static HRESULT SAFEARRAY_CopyData(SAFEARRAY *psa, SAFEARRAY *dest) { HRESULT hr = S_OK; if (!psa->pvData) return S_OK; if (!dest->pvData || psa->fFeatures & FADF_DATADELETED) return E_INVALIDARG; else { ULONG ulCellCount = SAFEARRAY_GetCellCount(psa); dest->fFeatures = (dest->fFeatures & FADF_CREATEVECTOR) | (psa->fFeatures & ~ignored_copy_features); if (psa->fFeatures & FADF_VARIANT) { VARIANT *src_var = psa->pvData; VARIANT *dest_var = dest->pvData; while(ulCellCount--) { HRESULT hRet; /* destination is cleared automatically */ hRet = VariantCopy(dest_var, src_var); if (FAILED(hRet)) FIXME("VariantCopy failed with 0x%08x, element %u\n", hRet, ulCellCount); src_var++; dest_var++; } } else if (psa->fFeatures & FADF_BSTR) { BSTR *src_bstr = psa->pvData; BSTR *dest_bstr = dest->pvData; while(ulCellCount--) { SysFreeString(*dest_bstr); if (*src_bstr) { *dest_bstr = SysAllocStringByteLen((char*)*src_bstr, SysStringByteLen(*src_bstr)); if (!*dest_bstr) return E_OUTOFMEMORY; } else *dest_bstr = NULL; src_bstr++; dest_bstr++; } } else if (psa->fFeatures & FADF_RECORD) { BYTE *dest_data = dest->pvData; BYTE *src_data = psa->pvData; IRecordInfo *record; SafeArrayGetRecordInfo(psa, &record); while (ulCellCount--) { /* RecordCopy() clears destination record */ hr = IRecordInfo_RecordCopy(record, src_data, dest_data); if (FAILED(hr)) break; src_data += psa->cbElements; dest_data += psa->cbElements; } SafeArraySetRecordInfo(dest, record); /* This value is set to 32 bytes by default on descriptor creation, update with actual structure size. */ dest->cbElements = psa->cbElements; IRecordInfo_Release(record); } else if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH)) { IUnknown **dest_unk = dest->pvData; IUnknown **src_unk = psa->pvData; /* release old iface, addref new one */ while (ulCellCount--) { if (*dest_unk) IUnknown_Release(*dest_unk); *dest_unk = *src_unk; if (*dest_unk) IUnknown_AddRef(*dest_unk); src_unk++; dest_unk++; } } else { /* Copy the data over */ memcpy(dest->pvData, psa->pvData, ulCellCount * psa->cbElements); } if (psa->fFeatures & FADF_HAVEIID) { GUID guid; SafeArrayGetIID(psa, &guid); SafeArraySetIID(dest, &guid); } else if (psa->fFeatures & FADF_HAVEVARTYPE) { SAFEARRAY_SetHiddenDWORD(dest, SAFEARRAY_GetHiddenDWORD(psa)); } } return hr; }
/* Free data items in an array */ static HRESULT SAFEARRAY_DestroyData(SAFEARRAY *psa, ULONG ulStartCell) { if (psa->pvData && !(psa->fFeatures & FADF_DATADELETED)) { ULONG ulCellCount = SAFEARRAY_GetCellCount(psa); if (ulStartCell > ulCellCount) { FIXME("unexpted ulcellcount %d, start %d\n",ulCellCount,ulStartCell); return E_UNEXPECTED; } ulCellCount -= ulStartCell; if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH)) { LPUNKNOWN *lpUnknown = (LPUNKNOWN *)psa->pvData + ulStartCell; while(ulCellCount--) { if (*lpUnknown) IUnknown_Release(*lpUnknown); lpUnknown++; } } else if (psa->fFeatures & FADF_RECORD) { IRecordInfo *lpRecInfo; if (SUCCEEDED(SafeArrayGetRecordInfo(psa, &lpRecInfo))) { PBYTE pRecordData = psa->pvData; while(ulCellCount--) { IRecordInfo_RecordClear(lpRecInfo, pRecordData); pRecordData += psa->cbElements; } IRecordInfo_Release(lpRecInfo); } } else if (psa->fFeatures & FADF_BSTR) { BSTR* lpBstr = (BSTR*)psa->pvData + ulStartCell; while(ulCellCount--) { SysFreeString(*lpBstr); lpBstr++; } } else if (psa->fFeatures & FADF_VARIANT) { VARIANT* lpVariant = (VARIANT*)psa->pvData + ulStartCell; while(ulCellCount--) { HRESULT hRet = VariantClear(lpVariant); if (FAILED(hRet)) FIXME("VariantClear of element failed!\n"); lpVariant++; } } } return S_OK; }
/************************************************************************ * SafeArrayRedim (OLEAUT32.40) * * Changes the characteristics of the last dimension of a SafeArray * * PARAMS * psa [I] Array to change * psabound [I] New bound details for the last dimension * * RETURNS * Success: S_OK. psa is updated to reflect the new bounds. * Failure: An HRESULT error code indicating the error. * * NOTES * See SafeArray. */ HRESULT WINAPI SafeArrayRedim(SAFEARRAY *psa, SAFEARRAYBOUND *psabound) { SAFEARRAYBOUND *oldBounds; HRESULT hr; TRACE("(%p,%p)\n", psa, psabound); if (!psa || psa->fFeatures & FADF_FIXEDSIZE || !psabound) return E_INVALIDARG; if (psa->cLocks > 0) return DISP_E_ARRAYISLOCKED; hr = SafeArrayLock(psa); if (FAILED(hr)) return hr; oldBounds = psa->rgsabound; oldBounds->lLbound = psabound->lLbound; if (psabound->cElements != oldBounds->cElements) { if (psabound->cElements < oldBounds->cElements) { /* Shorten the final dimension. */ ULONG ulStartCell = psabound->cElements * (SAFEARRAY_GetCellCount(psa) / oldBounds->cElements); SAFEARRAY_DestroyData(psa, ulStartCell); } else { /* Lengthen the final dimension */ ULONG ulOldSize, ulNewSize; PVOID pvNewData; ulOldSize = SAFEARRAY_GetCellCount(psa) * psa->cbElements; if (ulOldSize) ulNewSize = (ulOldSize / oldBounds->cElements) * psabound->cElements; else { int oldelems = oldBounds->cElements; oldBounds->cElements = psabound->cElements; ulNewSize = SAFEARRAY_GetCellCount(psa) * psa->cbElements; oldBounds->cElements = oldelems; } if (!(pvNewData = SAFEARRAY_Malloc(ulNewSize))) { SafeArrayUnlock(psa); return E_OUTOFMEMORY; } memcpy(pvNewData, psa->pvData, ulOldSize); SAFEARRAY_Free(psa->pvData); psa->pvData = pvNewData; } oldBounds->cElements = psabound->cElements; } SafeArrayUnlock(psa); return S_OK; }