Created
November 1, 2023 19:20
-
-
Save tannergooding/0f0fb2aaed16d88248e9b042f3551bdb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Diagnostics; | |
using System.Runtime.CompilerServices; | |
using System.Runtime.InteropServices; | |
using System.Runtime.Versioning; | |
using TerraFX.Interop; | |
using TerraFX.Interop.Windows; | |
using static TerraFX.Interop.Windows.E; | |
using static TerraFX.Interop.Windows.IID; | |
using static TerraFX.Interop.Windows.S; | |
[SupportedOSPlatform("windows6.1")] | |
public unsafe struct IStreamImpl : IStream.Interface | |
{ | |
private static readonly IStream.Vtbl<IStreamImpl>* Vtbl = InitVtbl(); | |
private IStream.Vtbl<IStreamImpl>* _vtbl; | |
private volatile uint _refCount; | |
public IStreamImpl() | |
{ | |
_vtbl = Vtbl; | |
_refCount = 1; | |
} | |
private static IStream.Vtbl<IStreamImpl>* InitVtbl() | |
{ | |
IStream.Vtbl<IStreamImpl>* vtbl = (IStream.Vtbl<IStreamImpl>*)(RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(IStreamImpl), sizeof(IStream.Vtbl<IStreamImpl>))); | |
// IUnknown | |
vtbl->QueryInterface = &QueryInterface; | |
vtbl->AddRef = &AddRef; | |
vtbl->Release = &Release; | |
// ISequentialStream | |
vtbl->Read = &Read; | |
vtbl->Write = &Write; | |
// IStream | |
vtbl->Seek = &Seek; | |
vtbl->SetSize = &SetSize; | |
vtbl->CopyTo = &CopyTo; | |
vtbl->Commit = &Commit; | |
vtbl->Revert = &Revert; | |
vtbl->LockRegion = &LockRegion; | |
vtbl->UnlockRegion = &UnlockRegion; | |
vtbl->Stat = &Stat; | |
vtbl->Clone = &Clone; | |
return vtbl; | |
} | |
#region Actual Implementation | |
[UnmanagedCallersOnly] | |
public static HRESULT QueryInterface(IStreamImpl* pThis, Guid* riid, void** ppvObject) | |
{ | |
if (ppvObject == null) | |
{ | |
return E_POINTER; | |
} | |
if (*riid == IID_IUnknown) | |
{ | |
_ = Interlocked.Increment(ref pThis->_refCount); | |
*ppvObject = pThis; | |
return S_OK; | |
} | |
*ppvObject = null; | |
return E_NOINTERFACE; | |
} | |
[UnmanagedCallersOnly] | |
private static uint AddRef(IStreamImpl* pThis) => Interlocked.Increment(ref pThis->_refCount); | |
[UnmanagedCallersOnly] | |
private static uint Release(IStreamImpl* pThis) | |
{ | |
uint newRefCount = Interlocked.Decrement(ref pThis->_refCount); | |
if (newRefCount == 0) | |
{ | |
// do any additional cleanup required | |
} | |
return newRefCount; | |
} | |
[UnmanagedCallersOnly] | |
private static HRESULT Read(IStreamImpl* pThis, void* pv, uint cb, uint* pcbRead) => E_NOTIMPL; | |
[UnmanagedCallersOnly] | |
private static HRESULT Write(IStreamImpl* pThis, void* pv, uint cb, uint* pcbWritten) => E_NOTIMPL; | |
[UnmanagedCallersOnly] | |
private static HRESULT Seek(IStreamImpl* pThis, LARGE_INTEGER dlibMove, uint dwOrigin, ULARGE_INTEGER* plibNewPosition) => E_NOTIMPL; | |
[UnmanagedCallersOnly] | |
private static HRESULT SetSize(IStreamImpl* pThis, ULARGE_INTEGER libNewSize) => E_NOTIMPL; | |
[UnmanagedCallersOnly] | |
private static HRESULT CopyTo(IStreamImpl* pThis, IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) => E_NOTIMPL; | |
[UnmanagedCallersOnly] | |
private static HRESULT Commit(IStreamImpl* pThis, uint grfCommitFlags) => E_NOTIMPL; | |
[UnmanagedCallersOnly] | |
private static HRESULT Revert(IStreamImpl* pThis) => E_NOTIMPL; | |
[UnmanagedCallersOnly] | |
private static HRESULT LockRegion(IStreamImpl* pThis, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, uint dwLockType) => E_NOTIMPL; | |
[UnmanagedCallersOnly] | |
private static HRESULT UnlockRegion(IStreamImpl* pThis, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, uint dwLockType) => E_NOTIMPL; | |
[UnmanagedCallersOnly] | |
private static HRESULT Stat(IStreamImpl* pThis, STATSTG* pstatstg, uint grfStatFlag) => E_NOTIMPL; | |
[UnmanagedCallersOnly] | |
private static HRESULT Clone(IStreamImpl* pThis, IStream** ppstm) => E_NOTIMPL; | |
#endregion | |
#region Helper APIs | |
public HRESULT QueryInterface(Guid* riid, void** ppvObject) => _vtbl->QueryInterface((IStreamImpl*)Unsafe.AsPointer(ref this), riid, ppvObject); | |
public uint AddRef() => _vtbl->AddRef((IStreamImpl*)Unsafe.AsPointer(ref this)); | |
public uint Release() => _vtbl->Release((IStreamImpl*)Unsafe.AsPointer(ref this)); | |
public HRESULT Read(void* pv, uint cb, uint* pcbRead) => _vtbl->Read((IStreamImpl*)Unsafe.AsPointer(ref this), pv, cb, pcbRead); | |
public HRESULT Write(void* pv, uint cb, uint* pcbWritten) => _vtbl->Write((IStreamImpl*)Unsafe.AsPointer(ref this), pv, cb, pcbWritten); | |
public HRESULT Seek(LARGE_INTEGER dlibMove, uint dwOrigin, ULARGE_INTEGER* plibNewPosition) => _vtbl->Seek((IStreamImpl*)Unsafe.AsPointer(ref this), dlibMove, dwOrigin, plibNewPosition); | |
public HRESULT SetSize(ULARGE_INTEGER libNewSize) => _vtbl->SetSize((IStreamImpl*)Unsafe.AsPointer(ref this), libNewSize); | |
public HRESULT CopyTo(IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) => _vtbl->CopyTo((IStreamImpl*)Unsafe.AsPointer(ref this), pstm, cb, pcbRead, pcbWritten); | |
public HRESULT Commit(uint grfCommitFlags) => _vtbl->Commit((IStreamImpl*)Unsafe.AsPointer(ref this), grfCommitFlags); | |
public HRESULT Revert() => _vtbl->Revert((IStreamImpl*)Unsafe.AsPointer(ref this)); | |
public HRESULT LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, uint dwLockType) => _vtbl->LockRegion((IStreamImpl*)Unsafe.AsPointer(ref this), libOffset, cb, dwLockType); | |
public HRESULT UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, uint dwLockType) => _vtbl->UnlockRegion((IStreamImpl*)Unsafe.AsPointer(ref this), libOffset, cb, dwLockType); | |
public HRESULT Stat(STATSTG* pstatstg, uint grfStatFlag) => _vtbl->Stat((IStreamImpl*)Unsafe.AsPointer(ref this), pstatstg, grfStatFlag); | |
public HRESULT Clone(IStream** ppstm) => _vtbl->Clone((IStreamImpl*)Unsafe.AsPointer(ref this), ppstm); | |
#endregion | |
static Guid* INativeGuid.NativeGuid | |
{ | |
get | |
{ | |
ReadOnlySpan<byte> data = [ | |
0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, | |
0x00, 0x00, | |
0x00, | |
0x00, | |
0x00, | |
0x00, | |
0x00, | |
0x00, | |
0x00, | |
0x00 | |
]; | |
Debug.Assert(data.Length == Unsafe.SizeOf<Guid>()); | |
return (Guid*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(data)); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Any idea why I get many this type of errors when I try to use the sample code?
Error CS0407 'HRESULT IStreamImpl.QueryInterface(IStreamImpl*, Guid*, void**)' has the wrong return type
Error CS0407 'HRESULT IStreamImpl.Read(IStreamImpl*, void*, uint, uint*)' has the wrong return type
Error CS0407 'HRESULT IStreamImpl.Write(IStreamImpl*, void*, uint, uint*)' has the wrong return type
....