Hans Leidekker : winhttp: Implement IWinHttpRequest::get_ResponseStream.

Alexandre Julliard julliard at wine.codeweavers.com
Mon Feb 16 10:01:21 CST 2015


Module: wine
Branch: master
Commit: 5505413a81c67547f72236674619c8ee9025a89c
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=5505413a81c67547f72236674619c8ee9025a89c

Author: Hans Leidekker <hans at codeweavers.com>
Date:   Mon Feb 16 14:41:47 2015 +0100

winhttp: Implement IWinHttpRequest::get_ResponseStream.

---

 dlls/winhttp/request.c       | 195 ++++++++++++++++++++++++++++++++++++++++++-
 dlls/winhttp/tests/winhttp.c |  63 ++++++++++++--
 2 files changed, 248 insertions(+), 10 deletions(-)

diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c
index 135a291..a12d73a 100644
--- a/dlls/winhttp/request.c
+++ b/dlls/winhttp/request.c
@@ -3695,12 +3695,203 @@ done:
     return HRESULT_FROM_WIN32( err );
 }
 
+struct stream
+{
+    IStream IStream_iface;
+    LONG    refs;
+    char   *data;
+    ULARGE_INTEGER pos, size;
+};
+
+static inline struct stream *impl_from_IStream( IStream *iface )
+{
+    return CONTAINING_RECORD( iface, struct stream, IStream_iface );
+}
+
+static HRESULT WINAPI stream_QueryInterface( IStream *iface, REFIID riid, void **obj )
+{
+    struct stream *stream = impl_from_IStream( iface );
+
+    TRACE("%p, %s, %p\n", stream, debugstr_guid(riid), obj);
+
+    if (IsEqualGUID( riid, &IID_IStream ) || IsEqualGUID( riid, &IID_IUnknown ))
+    {
+        *obj = iface;
+    }
+    else
+    {
+        FIXME("interface %s not implemented\n", debugstr_guid(riid));
+        return E_NOINTERFACE;
+    }
+    IStream_AddRef( iface );
+    return S_OK;
+}
+
+static ULONG WINAPI stream_AddRef( IStream *iface )
+{
+    struct stream *stream = impl_from_IStream( iface );
+    return InterlockedIncrement( &stream->refs );
+}
+
+static ULONG WINAPI stream_Release( IStream *iface )
+{
+    struct stream *stream = impl_from_IStream( iface );
+    LONG refs = InterlockedDecrement( &stream->refs );
+    if (!refs)
+    {
+        heap_free( stream->data );
+        heap_free( stream );
+    }
+    return refs;
+}
+
+static HRESULT WINAPI stream_Read( IStream *iface, void *buf, ULONG len, ULONG *read )
+{
+    struct stream *stream = impl_from_IStream( iface );
+    ULONG size;
+
+    if (stream->pos.QuadPart >= stream->size.QuadPart)
+    {
+        *read = 0;
+        return S_FALSE;
+    }
+
+    size = min( stream->size.QuadPart - stream->pos.QuadPart, len );
+    memcpy( buf, stream->data + stream->pos.QuadPart, size );
+    stream->pos.QuadPart += size;
+    *read = size;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI stream_Write( IStream *iface, const void *buf, ULONG len, ULONG *written )
+{
+    FIXME("\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI stream_Seek( IStream *iface, LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER *newpos )
+{
+    struct stream *stream = impl_from_IStream( iface );
+
+    if (origin == STREAM_SEEK_SET)
+        stream->pos.QuadPart = move.QuadPart;
+    else if (origin == STREAM_SEEK_CUR)
+        stream->pos.QuadPart += move.QuadPart;
+    else if (origin == STREAM_SEEK_END)
+        stream->pos.QuadPart = stream->size.QuadPart - move.QuadPart;
+
+    if (newpos) newpos->QuadPart = stream->pos.QuadPart;
+    return S_OK;
+}
+
+static HRESULT WINAPI stream_SetSize( IStream *iface, ULARGE_INTEGER newsize )
+{
+    FIXME("\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI stream_CopyTo( IStream *iface, IStream *stream, ULARGE_INTEGER len, ULARGE_INTEGER *read,
+                                     ULARGE_INTEGER *written )
+{
+    FIXME("\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI stream_Commit( IStream *iface, DWORD flags )
+{
+    FIXME("\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI stream_Revert( IStream *iface )
+{
+    FIXME("\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI stream_LockRegion( IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER len, DWORD locktype )
+{
+    FIXME("\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI stream_UnlockRegion( IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER len, DWORD locktype )
+{
+    FIXME("\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI stream_Stat( IStream *iface, STATSTG *stg, DWORD flag )
+{
+    FIXME("\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI stream_Clone( IStream *iface, IStream **stream )
+{
+    FIXME("\n");
+    return E_NOTIMPL;
+}
+
+static const IStreamVtbl stream_vtbl =
+{
+    stream_QueryInterface,
+    stream_AddRef,
+    stream_Release,
+    stream_Read,
+    stream_Write,
+    stream_Seek,
+    stream_SetSize,
+    stream_CopyTo,
+    stream_Commit,
+    stream_Revert,
+    stream_LockRegion,
+    stream_UnlockRegion,
+    stream_Stat,
+    stream_Clone
+};
+
 static HRESULT WINAPI winhttp_request_get_ResponseStream(
     IWinHttpRequest *iface,
     VARIANT *body )
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    struct winhttp_request *request = impl_from_IWinHttpRequest( iface );
+    DWORD err = ERROR_SUCCESS;
+    struct stream *stream;
+
+    TRACE("%p, %p\n", request, body);
+
+    if (!body) return E_INVALIDARG;
+
+    EnterCriticalSection( &request->cs );
+    if (request->state < REQUEST_STATE_SENT)
+    {
+        err = ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND;
+        goto done;
+    }
+    if (!(stream = heap_alloc( sizeof(*stream) )))
+    {
+        err = ERROR_OUTOFMEMORY;
+        goto done;
+    }
+    stream->IStream_iface.lpVtbl = &stream_vtbl;
+    stream->refs = 1;
+    if (!(stream->data = heap_alloc( request->offset )))
+    {
+        heap_free( stream );
+        err = ERROR_OUTOFMEMORY;
+        goto done;
+    }
+    memcpy( stream->data, request->buffer, request->offset );
+    stream->pos.QuadPart = 0;
+    stream->size.QuadPart = request->offset;
+    V_VT( body ) = VT_UNKNOWN;
+    V_UNKNOWN( body ) = (IUnknown *)&stream->IStream_iface;
+
+done:
+    LeaveCriticalSection( &request->cs );
+    return HRESULT_FROM_WIN32( err );
 }
 
 static HRESULT WINAPI winhttp_request_get_Option(
diff --git a/dlls/winhttp/tests/winhttp.c b/dlls/winhttp/tests/winhttp.c
index 2cad807..1423cef 100644
--- a/dlls/winhttp/tests/winhttp.c
+++ b/dlls/winhttp/tests/winhttp.c
@@ -2624,11 +2624,15 @@ static void test_IWinHttpRequest(void)
     IWinHttpRequest *req;
     BSTR method, url, username, password, response = NULL, status_text = NULL, headers = NULL;
     BSTR date, today, connection, value = NULL;
-    VARIANT async, empty, timeout, body, proxy_server, bypass_list, data;
+    VARIANT async, empty, timeout, body, body2, proxy_server, bypass_list, data;
     VARIANT_BOOL succeeded;
     LONG status;
     WCHAR todayW[WINHTTP_TIME_FORMAT_BUFSIZE];
     SYSTEMTIME st;
+    IStream *stream, *stream2;
+    LARGE_INTEGER pos;
+    char buf[128];
+    DWORD count;
 
     GetSystemTime( &st );
     WinHttpTimeFromSystemTime( &st, todayW );
@@ -2680,8 +2684,7 @@ static void test_IWinHttpRequest(void)
     hr = IWinHttpRequest_Abort( req );
     ok( hr == S_OK, "got %08x\n", hr );
 
-    hr = IWinHttpRequest_Release( req );
-    ok( hr == S_OK, "got %08x\n", hr );
+    IWinHttpRequest_Release( req );
 
     hr = CoCreateInstance( &CLSID_WinHttpRequest, NULL, CLSCTX_INPROC_SERVER, &IID_IWinHttpRequest, (void **)&req );
     ok( hr == S_OK, "got %08x\n", hr );
@@ -2714,8 +2717,7 @@ static void test_IWinHttpRequest(void)
     hr = IWinHttpRequest_Abort( req );
     ok( hr == S_OK, "got %08x\n", hr );
 
-    hr = IWinHttpRequest_Release( req );
-    ok( hr == S_OK, "got %08x\n", hr );
+    IWinHttpRequest_Release( req );
 
     hr = CoCreateInstance( &CLSID_WinHttpRequest, NULL, CLSCTX_INPROC_SERVER, &IID_IWinHttpRequest, (void **)&req );
     ok( hr == S_OK, "got %08x\n", hr );
@@ -2974,6 +2976,41 @@ static void test_IWinHttpRequest(void)
     hr = VariantClear( &body );
     ok( hr == S_OK, "got %08x\n", hr );
 
+    VariantInit( &body );
+    V_VT( &body ) = VT_ERROR;
+    hr = IWinHttpRequest_get_ResponseStream( req, &body );
+    ok( hr == S_OK, "got %08x\n", hr );
+    ok( V_VT( &body ) == VT_UNKNOWN, "got %08x\n", V_VT( &body ) );
+
+    hr = IUnknown_QueryInterface( V_UNKNOWN( &body ), &IID_IStream, (void **)&stream );
+    ok( hr == S_OK, "got %08x\n", hr );
+    ok( V_UNKNOWN( &body ) == (IUnknown *)stream, "got different interface pointer\n" );
+
+    buf[0] = 0;
+    count = 0xdeadbeef;
+    hr = IStream_Read( stream, buf, 128, &count );
+    ok( hr == S_OK, "got %08x\n", hr );
+    ok( count != 0xdeadbeef, "count not set\n" );
+    ok( buf[0], "no data\n" );
+
+    VariantInit( &body2 );
+    V_VT( &body2 ) = VT_ERROR;
+    hr = IWinHttpRequest_get_ResponseStream( req, &body2 );
+    ok( hr == S_OK, "got %08x\n", hr );
+    ok( V_VT( &body2 ) == VT_UNKNOWN, "got %08x\n", V_VT( &body2 ) );
+    ok( V_UNKNOWN( &body ) != V_UNKNOWN( &body2 ), "got same interface pointer\n" );
+
+    hr = IUnknown_QueryInterface( V_UNKNOWN( &body2 ), &IID_IStream, (void **)&stream2 );
+    ok( hr == S_OK, "got %08x\n", hr );
+    ok( V_UNKNOWN( &body2 ) == (IUnknown *)stream2, "got different interface pointer\n" );
+    IStream_Release( stream2 );
+
+    hr = VariantClear( &body );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    hr = VariantClear( &body2 );
+    ok( hr == S_OK, "got %08x\n", hr );
+
     hr = IWinHttpRequest_SetProxy( req, HTTPREQUEST_PROXYSETTING_PROXY, proxy_server, bypass_list );
     ok( hr == S_OK, "got %08x\n", hr );
 
@@ -3003,8 +3040,19 @@ static void test_IWinHttpRequest(void)
     hr = IWinHttpRequest_Abort( req );
     ok( hr == S_OK, "got %08x\n", hr );
 
-    hr = IWinHttpRequest_Release( req );
+    IWinHttpRequest_Release( req );
+
+    pos.QuadPart = 0;
+    IStream_Seek( stream, pos, STREAM_SEEK_SET, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    buf[0] = 0;
+    count = 0xdeadbeef;
+    hr = IStream_Read( stream, buf, 128, &count );
     ok( hr == S_OK, "got %08x\n", hr );
+    ok( count != 0xdeadbeef, "count not set\n" );
+    ok( buf[0], "no data\n" );
+    IStream_Release( stream );
 
     hr = CoCreateInstance( &CLSID_WinHttpRequest, NULL, CLSCTX_INPROC_SERVER, &IID_IWinHttpRequest, (void **)&req );
     ok( hr == S_OK, "got %08x\n", hr );
@@ -3020,8 +3068,7 @@ static void test_IWinHttpRequest(void)
     hr = IWinHttpRequest_WaitForResponse( req, timeout, &succeeded );
     ok( hr == S_OK, "got %08x\n", hr );
 
-    hr = IWinHttpRequest_Release( req );
-    ok( hr == S_OK, "got %08x\n", hr );
+    IWinHttpRequest_Release( req );
 
     SysFreeString( method );
     SysFreeString( url );




More information about the wine-cvs mailing list