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; }
/* 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; }