public void SAFEARRAY_CreateSingleDimension_GetProperties_Success(ushort vt, ushort expectedFeatures, uint expectedCbElements) { var saBound = new SAFEARRAYBOUND { cElements = 10, lLbound = 1 }; SAFEARRAY *psa = SafeArrayCreate((VARENUM)vt, 1, &saBound); Assert.True(psa != null); try { Assert.Equal(1u, psa->cDims); Assert.Equal((FADF)expectedFeatures, psa->fFeatures); Assert.Equal((uint)expectedCbElements, psa->cbElements); Assert.Equal(0u, psa->cLocks); Assert.True(psa->pvData != null); Assert.Equal(10u, psa->rgsabound[0].cElements); Assert.Equal(1, psa->rgsabound[0].lLbound); VARENUM arrayVt = VARENUM.EMPTY; HRESULT hr = SafeArrayGetVartype(psa, &arrayVt); Assert.Equal(HRESULT.S_OK, hr); Assert.Equal((VARENUM)vt, arrayVt); } finally { HRESULT hr = SafeArrayDestroy(psa); Assert.Equal(HRESULT.S_OK, hr); } }
static void HeapTransposeArray(SAFEARRAY *psa, Array array, VARENUM arrayType) { var indices = new int[array.Rank]; var lower = new int[array.Rank]; var upper = new int[array.Rank]; InternalTransposeArray(psa, array, arrayType, indices, lower, upper); }
static void StackTransposeArray(SAFEARRAY *psa, Array array, VARENUM arrayType) { Span <int> indices = stackalloc int[array.Rank]; Span <int> lower = stackalloc int[array.Rank]; Span <int> upper = stackalloc int[array.Rank]; InternalTransposeArray(psa, array, arrayType, indices, lower, upper); }
private static void TransposeArray(SAFEARRAY *psa, Array array, VARENUM arrayType) { if (array.Rank <= 32) { StackTransposeArray(psa, array, arrayType); } else { Debug.Fail("The CLR should not support arrays with more than 32 dimensions."); HeapTransposeArray(psa, array, arrayType); }
public void SAFEARRAY_CreateSingleDimensionRECORD_GetProperties_Success() { var saBound = new SAFEARRAYBOUND { cElements = 10, lLbound = 1 }; var record = new CustomRecordInfo(); IntPtr pRecord = Marshal.GetComInterfaceForObject <CustomRecordInfo, IRecordInfo>(record); try { SAFEARRAY *psa = SafeArrayCreateEx(VARENUM.RECORD, 1, &saBound, pRecord); Assert.True(psa != null); try { Assert.Equal(1u, psa->cDims); Assert.Equal(FADF.RECORD, psa->fFeatures); Assert.Equal((uint)sizeof(int), psa->cbElements); Assert.Equal(0u, psa->cLocks); Assert.True(psa->pvData != null); Assert.Equal(10u, psa->rgsabound[0].cElements); Assert.Equal(1, psa->rgsabound[0].lLbound); VARENUM arrayVt = VARENUM.EMPTY; HRESULT hr = SafeArrayGetVartype(psa, &arrayVt); Assert.Equal(HRESULT.S_OK, hr); Assert.Equal(VARENUM.RECORD, arrayVt); } finally { HRESULT hr = SafeArrayDestroy(psa); Assert.Equal(HRESULT.S_OK, hr); } } finally { Marshal.Release(pRecord); } }
static void InternalTransposeArray(SAFEARRAY *psa, Array array, VARENUM arrayType, Span <int> indices, Span <int> lower, Span <int> upper) { int lastIndex = array.Rank - 1; int i; for (i = 0; i < array.Rank; i++) { indices[i] = lower[i] = array.GetLowerBound(i); upper[i] = array.GetUpperBound(i); } // Loop through all the indices. while (true) { BeginMainLoop: SetArrayValue(psa, array, indices, lower, arrayType); for (i = lastIndex; i > 0;) { if (++indices[i] <= upper[i]) { goto BeginMainLoop; } indices[i] = lower[i]; --i; } // Special case for the first index, it must be enumerated only once if (++indices[0] > upper[0]) { break; } } }
private static object?ToArray(SAFEARRAY *psa, VARENUM vt) { if (psa is null) { return(null); } VARENUM arrayType = vt & ~VARENUM.ARRAY; Array array = CreateArrayFromSafeArray(psa, arrayType); HRESULT hr = SafeArrayLock(psa); Debug.Assert(hr == HRESULT.S_OK); try { if (array.Rank == 1) { switch (arrayType) { case VARENUM.I1: new Span <sbyte>(psa->pvData, array.Length) .CopyTo(GetSpan <sbyte>(array)); break; case VARENUM.UI1: new Span <byte>(psa->pvData, array.Length) .CopyTo(GetSpan <byte>(array)); break; case VARENUM.I2: new Span <short>(psa->pvData, array.Length) .CopyTo(GetSpan <short>(array)); break; case VARENUM.UI2: new Span <ushort>(psa->pvData, array.Length) .CopyTo(GetSpan <ushort>(array)); break; case VARENUM.I4: case VARENUM.INT: new Span <int>(psa->pvData, array.Length) .CopyTo(GetSpan <int>(array)); break; case VARENUM.UI4: case VARENUM.UINT: case VARENUM.ERROR: // Not explicitly mentioned in the docs but trivial to implement. new Span <uint>(psa->pvData, array.Length) .CopyTo(GetSpan <uint>(array)); break; case VARENUM.I8: new Span <long>(psa->pvData, array.Length) .CopyTo(GetSpan <long>(array)); break; case VARENUM.UI8: new Span <ulong>(psa->pvData, array.Length) .CopyTo(GetSpan <ulong>(array)); break; case VARENUM.R4: new Span <float>(psa->pvData, array.Length) .CopyTo(GetSpan <float>(array)); break; case VARENUM.R8: new Span <double>(psa->pvData, array.Length) .CopyTo(GetSpan <double>(array)); break; case VARENUM.BOOL: { var data = new Span <VARIANT_BOOL>(psa->pvData, array.Length); var result = GetSpan <bool>(array); for (int i = 0; i < data.Length; i++) { result[i] = data[i] != VARIANT_BOOL.FALSE; } break; } case VARENUM.DECIMAL: { var data = new Span <DECIMAL>(psa->pvData, array.Length); var result = GetSpan <decimal>(array); for (int i = 0; i < data.Length; i++) { result[i] = data[i].ToDecimal(); } break; } case VARENUM.CY: { var data = new Span <long>(psa->pvData, array.Length); var result = GetSpan <decimal>(array); for (int i = 0; i < data.Length; i++) { result[i] = decimal.FromOACurrency(data[i]); } break; } case VARENUM.DATE: { var data = new Span <double>(psa->pvData, array.Length); var result = GetSpan <DateTime>(array); for (int i = 0; i < data.Length; i++) { result[i] = DateTime.FromOADate(data[i]); } break; } case VARENUM.BSTR: { var data = new Span <IntPtr>(psa->pvData, array.Length); var result = GetSpan <string?>(array); for (int i = 0; i < data.Length; i++) { result[i] = Marshal.PtrToStringUni(data[i]); } break; } case VARENUM.DISPATCH: case VARENUM.UNKNOWN: { var data = new Span <IntPtr>(psa->pvData, array.Length); var result = GetSpan <object?>(array); for (int i = 0; i < data.Length; i++) { if (data[i] == IntPtr.Zero) { result[i] = null; } else { result[i] = Marshal.GetObjectForIUnknown(data[i]); } } break; } case VARENUM.VARIANT: { var data = new Span <VARIANT>(psa->pvData, array.Length); var result = GetSpan <object?>(array); for (int i = 0; i < data.Length; i++) { result[i] = data[i].ToObject(); } break; } case VARENUM.RECORD: throw new NotImplementedException(); default: throw new ArgumentException(string.Format(SR.COM2UnhandledVT, vt)); } } else if (array.Length != 0) { // CLR arrays are laid out in row-major order. // See CLI 8.9.1: https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-335.pdf // However, SAFEARRAYs are laid out in column-major order. // See https://docs.microsoft.com/en-us/previous-versions/windows/desktop/automat/array-manipulation-functions // Therefore, we need to transpose data. TransposeArray(psa, array, arrayType); } } finally { hr = SafeArrayUnlock(psa); Debug.Assert(hr == HRESULT.S_OK); } return(array); }
public HRESULT put_BootImageOptionsArray(SAFEARRAY *newVal) { return(((delegate * unmanaged <IFileSystemImage2 *, SAFEARRAY *, int>)(lpVtbl[58]))((IFileSystemImage2 *)Unsafe.AsPointer(ref this), newVal)); }
public HRESULT put_MultisessionInterfaces(SAFEARRAY *newVal) { return(((delegate * unmanaged <IFileSystemImage2 *, SAFEARRAY *, int>)(lpVtbl[56]))((IFileSystemImage2 *)Unsafe.AsPointer(ref this), newVal)); }
public static unsafe partial HRESULT SafeArrayGetVartype(SAFEARRAY *psa, Ole32.VARENUM *pvt);
public int put_MultisessionInterfaces([NativeTypeName("SAFEARRAY *")] SAFEARRAY *newVal) { return(((delegate * unmanaged <IFileSystemImage3 *, SAFEARRAY *, int>)(lpVtbl[56]))((IFileSystemImage3 *)Unsafe.AsPointer(ref this), newVal)); }
public unsafe static extern HRESULT SafeArrayLock(SAFEARRAY *psa);
public unsafe static extern HRESULT SafeArrayGetVartype(SAFEARRAY *psa, Ole32.VARENUM *pvt);
public unsafe static extern HRESULT SafeArrayGetRecordInfo(SAFEARRAY *psa, out IRecordInfo pRecInfo);
public static unsafe partial HRESULT SafeArrayUnlock(SAFEARRAY *psa);
public int put_BootImageOptionsArray([NativeTypeName("SAFEARRAY *")] SAFEARRAY *newVal) { return(((delegate * unmanaged <IFileSystemImage3 *, SAFEARRAY *, int>)(lpVtbl[58]))((IFileSystemImage3 *)Unsafe.AsPointer(ref this), newVal)); }
private static void SetArrayValue(SAFEARRAY *psa, Array array, Span <int> indices, Span <int> lowerBounds, VARENUM arrayType) {
public unsafe static extern uint SafeArrayGetElemsize(SAFEARRAY *psa);