inetcomm: Add an implementation of IVirtualStream.

Hans Leidekker hans at codeweavers.com
Fri Nov 7 06:37:19 CST 2008


This interface is undocumented but fortunately its name was enough
of a hint to create a sensible implementation. Used by Outlook when
retrieving or sending a mail.

 -Hans

diff --git a/dlls/inetcomm/inetcomm_main.c b/dlls/inetcomm/inetcomm_main.c
index 1d71877..22f1919 100644
--- a/dlls/inetcomm/inetcomm_main.c
+++ b/dlls/inetcomm/inetcomm_main.c
@@ -139,6 +139,7 @@ static cf mime_body_cf      = { &cf_vtbl, MimeBody_create };
 static cf mime_allocator_cf = { &cf_vtbl, MimeAllocator_create };
 static cf mime_message_cf   = { &cf_vtbl, MimeMessage_create };
 static cf mime_security_cf  = { &cf_vtbl, MimeSecurity_create };
+static cf virtual_stream_cf = { &cf_vtbl, VirtualStream_create };
 
 /***********************************************************************
  *              DllGetClassObject (INETCOMM.@)
@@ -177,6 +178,10 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
     {
         cf = (IClassFactory*) &mime_allocator_cf.lpVtbl;
     }
+    else if( IsEqualCLSID( rclsid, &CLSID_IVirtualStream ))
+    {
+        cf = (IClassFactory*) &virtual_stream_cf.lpVtbl;
+    }
 
     if ( !cf )
     {
diff --git a/dlls/inetcomm/inetcomm_private.h b/dlls/inetcomm/inetcomm_private.h
index 589f92c..036113c 100644
--- a/dlls/inetcomm/inetcomm_private.h
+++ b/dlls/inetcomm/inetcomm_private.h
@@ -78,6 +78,8 @@ HRESULT MimeAllocator_create(IUnknown *outer, void **obj);
 HRESULT MimeMessage_create(IUnknown *outer, void **obj);
 HRESULT MimeSecurity_create(IUnknown *outer, void **obj);
 
+HRESULT VirtualStream_create(IUnknown *outer, void **obj);
+
 HRESULT MimeInternational_Construct(IMimeInternational **internat);
 
 HRESULT SMTPTransportCF_Create(REFIID riid, LPVOID *ppv);
diff --git a/dlls/inetcomm/mimeole.c b/dlls/inetcomm/mimeole.c
index 07aa6bd..7b4e4b8 100644
--- a/dlls/inetcomm/mimeole.c
+++ b/dlls/inetcomm/mimeole.c
@@ -2989,3 +2989,304 @@ HRESULT WINAPI MimeOleGetAllocator(IMimeAllocator **alloc)
 {
     return MimeAllocator_create(NULL, (void**)alloc);
 }
+
+typedef struct
+{
+    IStreamVtbl *lpVtbl;
+    LONG refs;
+
+    char *buffer;
+    ULARGE_INTEGER size, allocated, pos;
+} virtual_stream_t;
+
+static HRESULT WINAPI virtual_stream_QueryInterface(
+        IStream* iface,
+        REFIID riid,
+        void **ppvObject)
+{
+    virtual_stream_t *This = (virtual_stream_t *)iface;
+
+    TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
+    *ppvObject = NULL;
+
+    if(IsEqualIID(riid, &IID_IUnknown) ||
+       IsEqualIID(riid, &IID_ISequentialStream) ||
+       IsEqualIID(riid, &IID_IStream) ||
+       IsEqualIID(riid, &IID_IVirtualStream))
+    {
+        IStream_AddRef(iface);
+        *ppvObject = iface;
+        return S_OK;
+    }
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI virtual_stream_AddRef(
+         IStream* iface)
+{
+    virtual_stream_t *This = (virtual_stream_t *)iface;
+
+    TRACE("(%p)\n", This);
+    return InterlockedIncrement(&This->refs);
+}
+
+static ULONG WINAPI virtual_stream_Release(
+        IStream* iface)
+{
+    virtual_stream_t *This = (virtual_stream_t *)iface;
+    LONG refs;
+
+    TRACE("(%p)\n", This);
+
+    refs = InterlockedDecrement(&This->refs);
+    if (!refs)
+    {
+        HeapFree(GetProcessHeap(), 0, This->buffer);
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+    return refs;
+}
+
+static HRESULT WINAPI virtual_stream_Read(
+        IStream* iface,
+        void *pv,
+        ULONG cb,
+        ULONG *pcbRead)
+{
+    virtual_stream_t *This = (virtual_stream_t *)iface;
+
+    TRACE("(%p, %d, %p)\n", pv, cb, pcbRead);
+
+    if (This->pos.QuadPart + cb > This->size.QuadPart)
+        cb = This->size.QuadPart - This->pos.QuadPart;
+
+    memcpy(pv, This->buffer + This->pos.QuadPart, cb);
+    if (pcbRead) *pcbRead = cb;
+    This->pos.QuadPart += cb;
+    return S_OK;
+}
+
+#define INITIAL_BUFFER_SIZE 4096
+
+static HRESULT WINAPI virtual_stream_Write(
+        IStream* iface,
+        const void *pv,
+        ULONG cb,
+        ULONG *pcbWritten)
+{
+    virtual_stream_t *This = (virtual_stream_t *)iface;
+    ULARGE_INTEGER size;
+
+    TRACE("(%p, %d, %p)\n", pv, cb, pcbWritten);
+
+    if (!This->buffer)
+    {
+        size.QuadPart = max(cb, INITIAL_BUFFER_SIZE);
+        This->buffer = HeapAlloc(GetProcessHeap(), 0, size.QuadPart);
+        if (!This->buffer) return E_OUTOFMEMORY;
+        This->allocated.QuadPart = size.QuadPart;
+    }
+    while (cb > This->allocated.QuadPart - This->pos.QuadPart)
+    {
+        size.QuadPart = This->allocated.QuadPart * 2; 
+        This->buffer = HeapReAlloc(GetProcessHeap(), 0, This->buffer, size.QuadPart);
+        if (!This->buffer) return E_OUTOFMEMORY;
+        This->allocated.QuadPart = size.QuadPart;
+    }
+    memcpy(This->buffer + This->pos.QuadPart, pv, cb);
+    if (pcbWritten) *pcbWritten = cb;
+    This->pos.QuadPart += cb;
+    return S_OK;
+}
+
+static HRESULT WINAPI virtual_stream_Seek(
+        IStream* iface,
+        LARGE_INTEGER dlibMove,
+        DWORD dwOrigin,
+        ULARGE_INTEGER *plibNewPosition)
+{
+    virtual_stream_t *This = (virtual_stream_t *)iface;
+    LARGE_INTEGER new_pos;
+
+    TRACE("(%08x.%08x, %x, %p)\n", dlibMove.u.HighPart, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
+
+    switch(dwOrigin)
+    {
+    case STREAM_SEEK_SET:
+        new_pos = dlibMove;
+        break;
+    case STREAM_SEEK_CUR:
+        new_pos.QuadPart = This->pos.QuadPart + dlibMove.QuadPart;
+        break;
+    case STREAM_SEEK_END:
+        new_pos.QuadPart = This->size.QuadPart + dlibMove.QuadPart;
+        break;
+    default:
+        return STG_E_INVALIDFUNCTION;
+    }
+
+    if (new_pos.QuadPart < 0) new_pos.QuadPart = 0;
+    else if (new_pos.QuadPart > This->size.QuadPart) new_pos.QuadPart = This->size.QuadPart;
+
+    This->pos.QuadPart = new_pos.QuadPart;
+
+    if (plibNewPosition) *plibNewPosition = This->pos;
+    return S_OK;
+}
+
+static HRESULT WINAPI virtual_stream_SetSize(
+        IStream* iface,
+        ULARGE_INTEGER libNewSize)
+{
+    virtual_stream_t *This = (virtual_stream_t *)iface;
+
+    TRACE("(%08x.%08x)\n", libNewSize.u.HighPart, libNewSize.u.LowPart);
+
+    This->size.QuadPart = libNewSize.QuadPart;
+    return S_OK;
+}
+
+static HRESULT WINAPI virtual_stream_CopyTo(
+        IStream *iface,
+        IStream *pstm,
+        ULARGE_INTEGER cb,
+        ULARGE_INTEGER *pcbRead,
+        ULARGE_INTEGER *pcbWritten)
+{
+    virtual_stream_t *This = (virtual_stream_t *)iface;
+    HRESULT hr = S_OK;
+    BYTE buffer[256];
+    ULONG bytes_read, bytes_written, copy_size;
+    ULARGE_INTEGER total_read;
+    ULARGE_INTEGER total_written;
+
+    TRACE("(%p, %08x.%08x, %p, %p)\n", pstm, cb.u.HighPart, cb.u.LowPart, pcbRead, pcbWritten);
+
+    total_read.QuadPart = 0;
+    total_written.QuadPart = 0;
+
+    if (cb.QuadPart == -1) cb.QuadPart = This->size.QuadPart;
+    while (cb.QuadPart > 0)
+    {
+        if (cb.QuadPart >= sizeof(buffer))
+            copy_size = sizeof(buffer);
+        else
+            copy_size = cb.u.LowPart;
+
+        hr = virtual_stream_Read(iface, buffer, copy_size, &bytes_read);
+        if (FAILED(hr)) break;
+
+        total_read.QuadPart += bytes_read;
+        if (bytes_read)
+        {
+            hr = IStream_Write(pstm, buffer, bytes_read, &bytes_written);
+            if (FAILED(hr)) break;
+            total_written.QuadPart += bytes_written;
+        }
+
+        if (bytes_read != copy_size)
+            cb.QuadPart = 0;
+        else
+            cb.QuadPart -= bytes_read;
+    }
+
+    if (pcbRead) pcbRead->QuadPart = total_read.QuadPart;
+    if (pcbWritten) pcbWritten->QuadPart = total_written.QuadPart;
+
+    return hr;
+}
+
+static HRESULT WINAPI virtual_stream_Commit(
+        IStream* iface,
+        DWORD grfCommitFlags)
+{
+    TRACE("(%08x)\n", grfCommitFlags);
+    return S_OK;
+}
+
+static HRESULT WINAPI virtual_stream_Revert(
+        IStream* iface)
+{
+    FIXME("()\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI virtual_stream_LockRegion(
+        IStream* iface,
+        ULARGE_INTEGER libOffset,
+        ULARGE_INTEGER cb,
+        DWORD dwLockType)
+{
+    FIXME("(%08x.%08x, %08x.%08x, %08x)\n", libOffset.u.HighPart, libOffset.u.LowPart,
+          cb.u.HighPart, cb.u.LowPart, dwLockType);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI virtual_stream_UnlockRegion(
+        IStream* iface,
+        ULARGE_INTEGER libOffset,
+        ULARGE_INTEGER cb,
+        DWORD dwLockType)
+{
+    FIXME("(%08x.%08x, %08x.%08x, %08x)\n", libOffset.u.HighPart, libOffset.u.LowPart,
+          cb.u.HighPart, cb.u.LowPart, dwLockType);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI virtual_stream_Stat(
+        IStream* iface,
+        STATSTG *pstatstg,
+        DWORD grfStatFlag)
+{
+    FIXME("(%p, %08x)\n", pstatstg, grfStatFlag);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI virtual_stream_Clone(
+        IStream* iface,
+        IStream **ppstm)
+{
+    FIXME("(%p)\n", ppstm);
+    return E_NOTIMPL;
+}
+
+static struct IStreamVtbl virtual_stream_vtbl =
+{
+    virtual_stream_QueryInterface,
+    virtual_stream_AddRef,
+    virtual_stream_Release,
+    virtual_stream_Read,
+    virtual_stream_Write,
+    virtual_stream_Seek,
+    virtual_stream_SetSize,
+    virtual_stream_CopyTo,
+    virtual_stream_Commit,
+    virtual_stream_Revert,
+    virtual_stream_LockRegion,
+    virtual_stream_UnlockRegion,
+    virtual_stream_Stat,
+    virtual_stream_Clone
+};
+
+HRESULT VirtualStream_create(IUnknown *outer, void **obj)
+{
+    virtual_stream_t *This;
+
+    TRACE("(%p, %p)\n", outer, obj);
+
+    *obj = NULL;
+    if (outer) return CLASS_E_NOAGGREGATION;
+
+    This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
+    if(!This) return E_OUTOFMEMORY;
+
+    This->lpVtbl = &virtual_stream_vtbl;
+    This->refs = 1;
+    This->buffer = NULL;
+    This->allocated.QuadPart = 0;
+    This->size.QuadPart = 0;
+    This->pos.QuadPart = 0;
+
+    *obj = (IStream*)&This->lpVtbl;
+    return S_OK;
+}
diff --git a/dlls/inetcomm/regsvr.c b/dlls/inetcomm/regsvr.c
index 4c7310c..8ac982e 100644
--- a/dlls/inetcomm/regsvr.c
+++ b/dlls/inetcomm/regsvr.c
@@ -464,6 +464,12 @@ static struct regsvr_coclass const coclass_list[] = {
         "inetcomm.dll",
         "Both"
     },
+    {   &CLSID_IVirtualStream,
+        "CLSID_IVirtualStream",
+        NULL,
+        "inetcomm.dll",
+        "Both"
+    },
     { NULL }			/* list terminator */
 };
 
diff --git a/include/mimeole.idl b/include/mimeole.idl
index d74cdb5..2e7f5d6 100644
--- a/include/mimeole.idl
+++ b/include/mimeole.idl
@@ -34,6 +34,7 @@ cpp_quote("DEFINE_GUID(CLSID_IMimeAllocator, 0xfd853cdd, 0x7f86, 0x11d0, 0x82, 0
 cpp_quote("DEFINE_GUID(CLSID_IMimeMessage,   0xfd853ce3, 0x7f86, 0x11d0, 0x82, 0x52, 0x0, 0xc0, 0x4f, 0xd8, 0x5a, 0xb4);")
 cpp_quote("DEFINE_GUID(CLSID_IMimeSecurity,  0xfd853cde, 0x7f86, 0x11d0, 0x82, 0x52, 0x0, 0xc0, 0x4f, 0xd8, 0x5a, 0xb4);")
 cpp_quote("DEFINE_GUID(CLSID_IVirtualStream, 0xfd853cdf, 0x7f86, 0x11d0, 0x82, 0x52, 0x0, 0xc0, 0x4f, 0xd8, 0x5a, 0xb4);")
+cpp_quote("DEFINE_GUID(IID_IVirtualStream, 0xc5588359, 0x7f86, 0x11d0, 0x82, 0x52, 0x0, 0xc0, 0x4f, 0xd8, 0x5a, 0xb4);")
 
 cpp_quote("#define MIME_E_REG_CREATE_KEY         0x800cce01")
 cpp_quote("#define MIME_E_REG_QUERY_INFO         0x800cce02")



More information about the wine-patches mailing list