Skip to content

Instantly share code, notes, and snippets.

@tannergooding
Created November 1, 2023 19:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tannergooding/0f0fb2aaed16d88248e9b042f3551bdb to your computer and use it in GitHub Desktop.
Save tannergooding/0f0fb2aaed16d88248e9b042f3551bdb to your computer and use it in GitHub Desktop.
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));
}
}
}
@ty010624
Copy link

ty010624 commented Nov 8, 2023

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
....

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment