Creating a Virtual File Based on IStream

BoxedApp SDK introduces the function BoxedAppSDK_CreateVirtualFileBasedOnIStream, which allows developers to create virtual files that operate over a custom IStream implementation.

This enables full control over how a virtual file behaves — reads, writes, seeking, cloning, and size handling — using standard COM interface methods.


Purpose

To provide greater flexibility in virtualization, BoxedApp SDK supports creating virtual files based on IStream, the standard COM interface.
This allows a developer to implement a file-like object whose contents and behavior are entirely user-defined.


Function Declaration

HANDLE BoxedAppSDK_CreateVirtualFileBasedOnIStream(
    LPCTSTR szPath,
    DWORD dwDesiredAccess,
    DWORD dwShareMode,
    LPSECURITY_ATTRIBUTES lpSecurityAttributes,
    DWORD dwCreationDisposition,
    DWORD dwFlagsAndAttributes,
    HANDLE hTemplateFile,
    LPSTREAM pStream
);

All parameters except the last one are identical to those of the standard CreateFile function.
The last parameter, pStream, is a pointer to an IStream interface that defines the file's behavior.


IStream Integration Details

When BoxedApp handles a virtual file created from an IStream:

  • For read operations, it calls IStream::Read.
  • For write operations, it calls IStream::Write.
  • To change the current position in the file, it uses IStream::Seek.
  • To obtain the file size, BoxedApp internally calls Seek to determine the end of the stream.

Example of how BoxedApp determines file size:

IStream* pStream;
...
LARGE_INTEGER liZero = { 0 };
ULARGE_INTEGER CurPos;
 
// Save current position
pStream->Seek(liZero, STREAM_SEEK_CUR, &CurPos);
 
// Move to the end
ULARGE_INTEGER SizeOfFile;
pStream->Seek(liZero, STREAM_SEEK_END, &SizeOfFile);
 
// Restore the file pointer
LARGE_INTEGER Pos;
Pos.QuadPart = CurPos.QuadPart;
 
ULARGE_INTEGER temp;
pStream->Seek(Pos, STREAM_SEEK_SET, &temp);

When a new HANDLE is created for an IStream-based virtual file, IStream::Clone is called.
The implementation of this method should create a new IStream instance with an independent file pointer.


Example 1: C++ Implementation (IStream over a Static Buffer)

Below is an example of how to implement a minimal in-memory file using IStream on top of a static buffer.

class CVirtualFilePointer;
class CMemoryFile;
 
class CMemoryFileLock
{
private:
    CMemoryFile* m_pMemoryFile;
public:
    CMemoryFileLock(CMemoryFile* pMemoryFile);
    ~CMemoryFileLock();
};
 
// A file based on fixed memory block
class CMemoryFile
{
    friend class CVirtualFilePointer;
    friend class CMemoryFileLock;
 
private:
    LONG m_nRefCount;
    PBYTE m_p;
    DWORD m_dwSize;
    CRITICAL_SECTION m_cs;
 
private:
    CMemoryFile(PVOID p, DWORD size);
    ~CMemoryFile();
 
    IStream* CreateStream();
    void AddRef();
    void Release();
public:
    static IStream* Create(PVOID p, DWORD size);
};
 
class CVirtualFilePointer : public IStream
{
    friend class CVirtualFile;
 
private:
    LONG m_nRefCount;
    CMemoryFile* m_pFile;
    DWORD m_dwPosition;
 
public:
    CVirtualFilePointer(CMemoryFile* pMemoryFile) : 
        m_nRefCount(1), 
        m_dwPosition(0)
    {
        m_pFile = pMemoryFile;
        m_pFile->AddRef();
    }
 
    virtual ~CVirtualFilePointer()
    {
        m_pFile->Release();
    }
 
protected:
    // IUnknown
    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject)
    {
        *ppvObject = NULL;
 
        if (IsEqualIID(IID_IUnknown, riid))
            *ppvObject = this;
        else if (IsEqualIID(IID_IStream, riid))
            *ppvObject = this;
        else if (IsEqualIID(IID_ISequentialStream, riid))
            *ppvObject = this;
 
        if (NULL != *ppvObject)
        {
            AddRef();
            return S_OK;
        }
        else
            return E_NOINTERFACE;
    }
     
    virtual ULONG STDMETHODCALLTYPE AddRef()
    {
        InterlockedIncrement(&m_nRefCount);
        return m_nRefCount;
    }
     
    virtual ULONG STDMETHODCALLTYPE Release()
    {
        InterlockedDecrement(&m_nRefCount);
 
        LONG nRefCount = m_nRefCount;
 
        if (0 == m_nRefCount)
            delete this;
 
        return nRefCount;
    }
 
    // ISequentialStream
    virtual HRESULT STDMETHODCALLTYPE Read(void* pv, ULONG cb, ULONG* pcbRead)
    {
        CMemoryFileLock lock(m_pFile);
 
        DWORD dwBytesToRead;
 
        if (m_dwPosition < 0 || m_dwPosition > m_pFile->m_dwSize)
            dwBytesToRead = 0;
        else
            dwBytesToRead = cb < m_pFile->m_dwSize - m_dwPosition ? 
cb : m_pFile->m_dwSize - m_dwPosition;
 
        CopyMemory(pv, m_pFile->m_p + m_dwPosition, dwBytesToRead);
 
        m_dwPosition += dwBytesToRead;
 
        if (NULL != pcbRead)
            *pcbRead = dwBytesToRead;
 
        return S_OK;
    }
     
    virtual HRESULT STDMETHODCALLTYPE Write(const void* pv, ULONG cb, ULONG* pcbWritten)
    {
        CMemoryFileLock lock(m_pFile);
 
        DWORD dwBytesToWrite;
         
        if (m_dwPosition < 0 || m_dwPosition > m_pFile->m_dwSize)
            dwBytesToWrite = 0;
        else
            dwBytesToWrite = cb < m_pFile->m_dwSize - m_dwPosition ? 
cb : m_pFile->m_dwSize - m_dwPosition;
 
        CopyMemory(m_pFile->m_p + m_dwPosition, pv, dwBytesToWrite);
 
        m_dwPosition += dwBytesToWrite;
 
        if (NULL != pcbWritten)
            *pcbWritten = dwBytesToWrite;
 
        return S_OK;
    }
 
    // IStream
    virtual HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition)
    {
        CMemoryFileLock lock(m_pFile);
 
        // Note: new position can be more than m_dwSize
 
        switch (dwOrigin)
        {
            case STREAM_SEEK_CUR:
            {
                m_dwPosition += dlibMove.QuadPart;
                break;
            }
            case STREAM_SEEK_END:
            {
                m_dwPosition = m_pFile->m_dwSize + dlibMove.QuadPart;
                break;
            }
            case STREAM_SEEK_SET:
            {
                m_dwPosition = dlibMove.QuadPart;
                break;
            }
            default:
            {
                return E_FAIL;
            }
        }
 
        if (NULL != plibNewPosition)
            plibNewPosition->QuadPart = m_dwPosition;
 
        return S_OK;
    }
     
    virtual HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER libNewSize)
    {
        return E_NOTIMPL;
    }
 
    virtual HRESULT STDMETHODCALLTYPE Clone(IStream** ppstm)
    {
        *ppstm = m_pFile->CreateStream();
        return S_OK;
    }
     
    virtual HRESULT STDMETHODCALLTYPE CopyTo(IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten){return E_NOTIMPL;}    
    virtual HRESULT STDMETHODCALLTYPE Commit(DWORD grfCommitFlags){return E_NOTIMPL;}
    virtual HRESULT STDMETHODCALLTYPE Revert(){return E_NOTIMPL;}    
    virtual HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType){return E_NOTIMPL;}    
    virtual HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType){return E_NOTIMPL;}    
    virtual HRESULT STDMETHODCALLTYPE Stat(STATSTG* pstatstg, DWORD grfStatFlag){return E_NOTIMPL;}
};
 
CMemoryFileLock::CMemoryFileLock(CMemoryFile* pMemoryFile) : 
    m_pMemoryFile(pMemoryFile)
{
    EnterCriticalSection(&pMemoryFile->m_cs);
}
 
CMemoryFileLock::~CMemoryFileLock()
{
    LeaveCriticalSection(&m_pMemoryFile->m_cs);
}
 
CMemoryFile::CMemoryFile(PVOID p, DWORD size) : 
    m_p((PBYTE)p), 
    m_dwSize(size), 
    m_nRefCount(0)
{
    InitializeCriticalSection(&m_cs);
}
 
CMemoryFile::~CMemoryFile()
{
    DeleteCriticalSection(&m_cs);
}
 
IStream* CMemoryFile::CreateStream()
{
    return new CVirtualFilePointer(this);
}
 
void CMemoryFile::AddRef()
{
    InterlockedIncrement(&m_nRefCount);
}
 
void CMemoryFile::Release()
{
    InterlockedDecrement(&m_nRefCount);
 
    if (0 == m_nRefCount)
        delete this;
}
 
IStream* CMemoryFile::Create(PVOID p, DWORD size)
{
    CMemoryFile* pMemoryFile = new CMemoryFile(p, size);
    return pMemoryFile->CreateStream();
}

This implementation creates a virtual file that behaves like a normal file but stores data in memory rather than on disk.


Example 2: C# Implementation (Partial Stream-Based Virtual File)

The following C# sample shows how to use IStream to map a subsection of a file into a virtual file.
This approach allows the packed or virtualized application to work with only part of a physical file.

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.IO;
 
namespace Sample3_CustomVirtualFileSystem
{
    class CustomFileStream : IStream
    {
        private long _Offset;
        private long _Length;
        private string _FilePath;
        private Stream _Stream;
 
        public CustomFileStream(string FilePath, long Offset, long Length)
        {
            _FilePath = FilePath;
            _Stream = new FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.Read);
            _Offset = Offset;
            _Length = Length;
        }
 
        public CustomFileStream(string FilePath, long Offset)
        {
            _FilePath = FilePath;
            _Stream = new FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.Read);
            _Offset = Offset;
            _Length = _Stream.Length - _Offset;
        }
 
        #region IStream Members
 
        public void Read(byte[] pv, int cb, IntPtr pcbRead)
        {
            if (_Stream.Position > _Offset + _Length)
                cb = 0;
            else if (_Stream.Position + cb > _Offset + _Length)
                cb = (int)(_Offset + _Length - _Stream.Position);
 
            int nReadBytes = _Stream.Read(pv, 0, cb);
 
            if (IntPtr.Zero != pcbRead)
                Marshal.WriteIntPtr(pcbRead, new IntPtr(nReadBytes));
        }
 
        public void Write(byte[] pv, int cb, IntPtr pcbWritten)
        {
            if (_Stream.Position > _Offset + _Length)
                cb = 0;
            else if (_Stream.Position + cb > _Offset + _Length)
                cb = (int)(_Offset + _Length - _Stream.Position);
 
            int nWrittenBytes = _Stream.Read(pv, 0, cb);
 
            if (IntPtr.Zero != pcbWritten)
                Marshal.WriteIntPtr(pcbWritten, new IntPtr(nWrittenBytes));
        }
 
        public void Clone(out IStream ppstm)
        {
            ppstm = new CustomFileStream(_FilePath, _Offset, _Length);
        }
 
        public void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition)
        {
            SeekOrigin Origin = (SeekOrigin)dwOrigin;
            long NewPosition = 0;
 
            switch (Origin)
            {
                case SeekOrigin.Begin:
                    {
                        NewPosition = _Stream.Seek(_Offset + dlibMove, Origin);
 
                        break;
                    }
                case SeekOrigin.Current:
                    {
                        NewPosition = _Stream.Seek(dlibMove, Origin);
 
                        break;
                    }
                case SeekOrigin.End:
                    {
                        NewPosition = _Stream.Seek(_Offset + _Length + dlibMove, SeekOrigin.Begin);
 
                        break;
                    }
            }
 
            NewPosition -= _Offset;
 
            if (NewPosition < 0)
                NewPosition = 0;
            else if (NewPosition > _Length)
                NewPosition = _Length;
 
            if (IntPtr.Zero != plibNewPosition)
                Marshal.WriteInt64(plibNewPosition, NewPosition);
        }
 
        public void Commit(int grfCommitFlags)
        {
            throw new Exception("The method or operation is not implemented.");
        }
 
        public void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten)
        {
            throw new Exception("The method or operation is not implemented.");
        }
 
        public void LockRegion(long libOffset, long cb, int dwLockType)
        {
            throw new Exception("The method or operation is not implemented.");
        }
 
        public void Revert()
        {
            throw new Exception("The method or operation is not implemented.");
        }
 
        public void SetSize(long libNewSize)
        {
            throw new Exception("The method or operation is not implemented.");
        }
 
        public void Stat(out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg, int grfStatFlag)
        {
            throw new Exception("The method or operation is not implemented.");
        }
 
        public void UnlockRegion(long libOffset, long cb, int dwLockType)
        {
            throw new Exception("The method or operation is not implemented.");
        }
 
        #endregion
    }
}

Conclusion

By implementing IStream, developers can define completely custom storage backends for virtual files — memory buffers, embedded resources, database BLOBs, network streams, or encrypted containers.
This makes BoxedApp SDK not only a file packer but also a flexible virtualization framework for complex application scenarios.

✅ The SDK includes full C++, C#, VB.NET, Delphi, and VB6 samples demonstrating this approach.
Download the demo version


See Also