[6/6] winhttp: Support asynchronous requests.

Hans Leidekker hans at codeweavers.com
Sun Sep 7 14:36:40 CDT 2008


diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c
index ea08b5c..d1fc005 100644
--- a/dlls/winhttp/request.c
+++ b/dlls/winhttp/request.c
@@ -172,6 +172,22 @@ static const WCHAR *attribute_table[] =
     NULL                            /* WINHTTP_QUERY_PASSPORT_CONFIG            = 78 */
 };
 
+static DWORD CALLBACK task_thread( LPVOID param )
+{
+    task_header_t *task = param;
+
+    task->proc( task );
+
+    release_object( &task->request->hdr );
+    heap_free( task );
+    return ERROR_SUCCESS;
+}
+
+static BOOL queue_task( task_header_t *task )
+{
+    return QueueUserWorkItem( task_thread, task, WT_EXECUTELONGFUNCTION );
+}
+
 static void free_header( header_t *header )
 {
     heap_free( header->field );
@@ -776,7 +792,7 @@ static BOOL add_host_header( request_t *request, WCHAR *hostname, INTERNET_PORT
 }
 
 static BOOL send_request( request_t *request, LPCWSTR headers, DWORD headers_len, LPVOID optional,
-                          DWORD optional_len, DWORD total_len, DWORD_PTR context )
+                          DWORD optional_len, DWORD total_len, DWORD_PTR context, BOOL async )
 {
     static const WCHAR keep_alive[] = {'K','e','e','p','-','A','l','i','v','e',0};
     static const WCHAR no_cache[]   = {'n','o','-','c','a','c','h','e',0};
@@ -837,10 +853,28 @@ static BOOL send_request( request_t *request, LPCWSTR headers, DWORD headers_len
     send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_SENT, &len, sizeof(DWORD) );
 
 end:
+    if (async)
+    {
+        if (ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NULL, 0 );
+        else
+        {
+            WINHTTP_ASYNC_RESULT result;
+            result.dwResult = API_SEND_REQUEST;
+            result.dwError  = get_last_error();
+            send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) );
+        }
+    }
     heap_free( req );
     return ret;
 }
 
+static void task_send_request( task_header_t *task )
+{
+    send_request_t *s = (send_request_t *)task;
+    send_request( s->hdr.request, s->headers, s->headers_len, s->optional, s->optional_len, s->total_len, s->context, TRUE );
+    heap_free( s->headers );
+}
+
 /***********************************************************************
  *          WinHttpSendRequest (winhttp.@)
  */
@@ -865,19 +899,26 @@ BOOL WINAPI WinHttpSendRequest( HINTERNET hrequest, LPCWSTR headers, DWORD heade
         return FALSE;
     }
 
-    ret = send_request( request, headers, headers_len, optional, optional_len, total_len, context );
-
     if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC)
     {
-        if (ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NULL, 0 );
-        else
-        {
-            WINHTTP_ASYNC_RESULT async;
-            async.dwResult = API_SEND_REQUEST;
-            async.dwError  = get_last_error();
-            send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &async, sizeof(async) );
-        }
+        send_request_t *s;
+
+        if (!(s = heap_alloc( sizeof(send_request_t) ))) return FALSE;
+        s->hdr.request  = request;
+        s->hdr.proc     = task_send_request;
+        s->headers      = strdupW( headers );
+        s->headers_len  = headers_len;
+        s->optional     = optional;
+        s->optional_len = optional_len;
+        s->total_len    = total_len;
+        s->context      = context;
+
+        addref_object( &request->hdr );
+        ret = queue_task( (task_header_t *)s );
     }
+    else
+        ret = send_request( request, headers, headers_len, optional, optional_len, total_len, context, FALSE );
+
     release_object( &request->hdr );
     return ret;
 }
@@ -899,7 +940,7 @@ static void clear_response_headers( request_t *request )
 #define MAX_REPLY_LEN   1460
 #define INITIAL_HEADER_BUFFER_LEN  512
 
-static BOOL receive_response( request_t *request, BOOL clear )
+static BOOL read_reply( request_t *request, BOOL clear )
 {
     static const WCHAR crlf[] = {'\r','\n',0};
 
@@ -1070,7 +1111,7 @@ end:
     return ret;
 }
 
-static BOOL read_data( request_t *request, void *buffer, DWORD size, DWORD *read, BOOL async )
+static BOOL receive_data( request_t *request, void *buffer, DWORD size, DWORD *read, BOOL async )
 {
     DWORD to_read;
     int bytes_read;
@@ -1100,36 +1141,18 @@ static void drain_content( request_t *request )
     if (request->content_length == ~0UL) return;
     for (;;)
     {
-        if (!read_data( request, buffer, sizeof(buffer), &bytes_read, FALSE ) || !bytes_read) return;
+        if (!receive_data( request, buffer, sizeof(buffer), &bytes_read, FALSE ) || !bytes_read) return;
     }
 }
 
-/***********************************************************************
- *          WinHttpReceiveResponse (winhttp.@)
- */
-BOOL WINAPI WinHttpReceiveResponse( HINTERNET hrequest, LPVOID reserved )
+static BOOL receive_response( request_t *request, BOOL async )
 {
-    BOOL ret = TRUE;
-    request_t *request;
+    BOOL ret;
     DWORD size, query, status;
 
-    TRACE("%p, %p\n", hrequest, reserved);
-
-    if (!(request = (request_t *)grab_object( hrequest )))
-    {
-        set_last_error( ERROR_INVALID_HANDLE );
-        return FALSE;
-    }
-    if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST)
-    {
-        release_object( &request->hdr );
-        set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
-        return FALSE;
-    }
-
     for (;;)
     {
-        if (!(ret = receive_response( request, TRUE ))) break;
+        if (!(ret = read_reply( request, TRUE ))) break;
 
         size = sizeof(DWORD);
         query = WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER;
@@ -1147,34 +1170,38 @@ BOOL WINAPI WinHttpReceiveResponse( HINTERNET hrequest, LPVOID reserved )
             drain_content( request );
             if (!(ret = handle_redirect( request ))) break;
         }
-        ret = send_request( request, NULL, 0, NULL, 0, 0, 0 );
+        ret = send_request( request, NULL, 0, NULL, 0, 0, 0, FALSE ); /* recurse synchronously */
     }
 
-    if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC)
+    if (async)
     {
         if (ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NULL, 0 );
         else
         {
-            WINHTTP_ASYNC_RESULT async;
-            async.dwResult = API_RECEIVE_RESPONSE;
-            async.dwError  = get_last_error();
-            send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &async, sizeof(async) );
+            WINHTTP_ASYNC_RESULT result;
+            result.dwResult = API_RECEIVE_RESPONSE;
+            result.dwError  = get_last_error();
+            send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) );
         }
     }
-    release_object( &request->hdr );
     return ret;
 }
 
+static void task_receive_response( task_header_t *task )
+{
+    receive_response_t *r = (receive_response_t *)task;
+    receive_response( r->hdr.request, TRUE );
+}
+
 /***********************************************************************
- *          WinHttpQueryDataAvailable (winhttp.@)
+ *          WinHttpReceiveResponse (winhttp.@)
  */
-BOOL WINAPI WinHttpQueryDataAvailable( HINTERNET hrequest, LPDWORD available )
+BOOL WINAPI WinHttpReceiveResponse( HINTERNET hrequest, LPVOID reserved )
 {
     BOOL ret;
-    DWORD num_bytes;
     request_t *request;
 
-    TRACE("%p, %p\n", hrequest, available);
+    TRACE("%p, %p\n", hrequest, reserved);
 
     if (!(request = (request_t *)grab_object( hrequest )))
     {
@@ -1188,20 +1215,89 @@ BOOL WINAPI WinHttpQueryDataAvailable( HINTERNET hrequest, LPDWORD available )
         return FALSE;
     }
 
+    if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC)
+    {
+        receive_response_t *r;
+
+        if (!(r = heap_alloc( sizeof(receive_response_t) ))) return FALSE;
+        r->hdr.request = request;
+        r->hdr.proc    = task_receive_response;
+
+        addref_object( &request->hdr );
+        ret = queue_task( (task_header_t *)r );
+    }
+    else
+        ret = receive_response( request, FALSE );
+
+    release_object( &request->hdr );
+    return ret;
+}
+
+static BOOL query_data( request_t *request, LPDWORD available, BOOL async )
+{
+    BOOL ret;
+    DWORD num_bytes;
+
     ret = netconn_query_data_available( &request->netconn, &num_bytes );
 
-    if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC)
+    if (async)
     {
         if (ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE, &num_bytes, sizeof(DWORD) );
         else
         {
-            WINHTTP_ASYNC_RESULT async;
-            async.dwResult = API_QUERY_DATA_AVAILABLE;
-            async.dwError  = get_last_error();
-            send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &async, sizeof(async) );
+            WINHTTP_ASYNC_RESULT result;
+            result.dwResult = API_QUERY_DATA_AVAILABLE;
+            result.dwError  = get_last_error();
+            send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) );
         }
     }
     if (ret && available) *available = num_bytes;
+    return ret;
+}
+
+static void task_query_data( task_header_t *task )
+{
+    query_data_t *q = (query_data_t *)task;
+    query_data( q->hdr.request, q->available, TRUE );
+}
+
+/***********************************************************************
+ *          WinHttpQueryDataAvailable (winhttp.@)
+ */
+BOOL WINAPI WinHttpQueryDataAvailable( HINTERNET hrequest, LPDWORD available )
+{
+    BOOL ret;
+    request_t *request;
+
+    TRACE("%p, %p\n", hrequest, available);
+
+    if (!(request = (request_t *)grab_object( hrequest )))
+    {
+        set_last_error( ERROR_INVALID_HANDLE );
+        return FALSE;
+    }
+    if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST)
+    {
+        release_object( &request->hdr );
+        set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
+        return FALSE;
+    }
+
+    if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC)
+    {
+        query_data_t *q;
+
+        if (!(q = heap_alloc( sizeof(query_data_t) ))) return FALSE;
+        q->hdr.request = request;
+        q->hdr.proc    = task_query_data;
+        q->available   = available;
+
+        addref_object( &request->hdr );
+        ret = queue_task( (task_header_t *)q );
+    }
+    else
+        ret = query_data( request, available, FALSE );
+
     release_object( &request->hdr );
     return ret;
 }
@@ -1221,7 +1317,7 @@ static DWORD get_chunk_size( const char *buffer )
     return size;
 }
 
-static BOOL read_data_chunked( request_t *request, void *buffer, DWORD size, DWORD *read, BOOL async )
+static BOOL receive_data_chunked( request_t *request, void *buffer, DWORD size, DWORD *read, BOOL async )
 {
     char reply[MAX_REPLY_LEN], *p = buffer;
     DWORD buflen, to_read, to_write = size;
@@ -1240,7 +1336,7 @@ static BOOL read_data_chunked( request_t *request, void *buffer, DWORD size, DWO
             if (!(request->content_length = get_chunk_size( reply )))
             {
                 /* zero sized chunk marks end of transfer; read any trailing headers and return */
-                receive_response( request, FALSE );
+                read_reply( request, FALSE );
                 break;
             }
         }
@@ -1280,17 +1376,50 @@ static BOOL read_data_chunked( request_t *request, void *buffer, DWORD size, DWO
     return TRUE;
 }
 
+static BOOL read_data( request_t *request, void *buffer, DWORD to_read, DWORD *read, BOOL async )
+{
+    static const WCHAR chunked[] = {'c','h','u','n','k','e','d',0};
+
+    BOOL ret;
+    WCHAR encoding[20];
+    DWORD num_bytes, buflen = sizeof(encoding);
+
+    if (query_headers( request, WINHTTP_QUERY_TRANSFER_ENCODING, NULL, encoding, &buflen, NULL ) &&
+        !strcmpiW( encoding, chunked ))
+    {
+        ret = receive_data_chunked( request, buffer, to_read, &num_bytes, async );
+    }
+    else
+        ret = receive_data( request, buffer, to_read, &num_bytes, async );
+
+    if (async)
+    {
+        if (ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, buffer, num_bytes );
+        else
+        {
+            WINHTTP_ASYNC_RESULT result;
+            result.dwResult = API_READ_DATA;
+            result.dwError  = get_last_error();
+            send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) );
+        }
+    }
+    if (ret && read) *read = num_bytes;
+    return ret;
+}
+
+static void task_read_data( task_header_t *task )
+{
+    read_data_t *r = (read_data_t *)task;
+    read_data( r->hdr.request, r->buffer, r->to_read, r->read, TRUE );
+}
+
 /***********************************************************************
  *          WinHttpReadData (winhttp.@)
  */
 BOOL WINAPI WinHttpReadData( HINTERNET hrequest, LPVOID buffer, DWORD to_read, LPDWORD read )
 {
-    static const WCHAR chunked[] = {'c','h','u','n','k','e','d',0};
-
-    BOOL ret, async;
+    BOOL ret;
     request_t *request;
-    WCHAR encoding[20];
-    DWORD num_bytes, buflen = sizeof(encoding);
 
     TRACE("%p, %p, %d, %p\n", hrequest, buffer, to_read, read);
 
@@ -1306,38 +1435,61 @@ BOOL WINAPI WinHttpReadData( HINTERNET hrequest, LPVOID buffer, DWORD to_read, L
         return FALSE;
     }
 
-    async = request->connect->hdr.flags & WINHTTP_FLAG_ASYNC;
-    if (query_headers( request, WINHTTP_QUERY_TRANSFER_ENCODING, NULL, encoding, &buflen, NULL ) &&
-        !strcmpiW( encoding, chunked ))
+    if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC)
     {
-        ret = read_data_chunked( request, buffer, to_read, &num_bytes, async );
+        read_data_t *r;
+
+        if (!(r = heap_alloc( sizeof(read_data_t) ))) return FALSE;
+        r->hdr.request = request;
+        r->hdr.proc    = task_read_data;
+        r->buffer      = buffer;
+        r->to_read     = to_read;
+        r->read        = read;
+
+        addref_object( &request->hdr );
+        ret = queue_task( (task_header_t *)r );
     }
     else
-        ret = read_data( request, buffer, to_read, &num_bytes, async );
+        ret = read_data( request, buffer, to_read, read, FALSE );
+
+    release_object( &request->hdr );
+    return ret;
+}
+
+static BOOL write_data( request_t *request, LPCVOID buffer, DWORD to_write, LPDWORD written, BOOL async )
+{
+    BOOL ret;
+    int num_bytes;
+
+    ret = netconn_send( &request->netconn, buffer, to_write, 0, &num_bytes );
 
     if (async)
     {
-        if (ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, buffer, num_bytes );
+        if (ret) send_callback( &request->hdr, WINHTTP_CALLBACK_FLAG_WRITE_COMPLETE, &num_bytes, sizeof(DWORD) );
         else
         {
-            WINHTTP_ASYNC_RESULT async;
-            async.dwResult = API_READ_DATA;
-            async.dwError  = get_last_error();
-            send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &async, sizeof(async) );
+            WINHTTP_ASYNC_RESULT result;
+            result.dwResult = API_WRITE_DATA;
+            result.dwError  = get_last_error();
+            send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) );
         }
     }
-    if (ret && read) *read = num_bytes;
-    release_object( &request->hdr );
+    if (ret && written) *written = num_bytes;
     return ret;
 }
 
+static void task_write_data( task_header_t *task )
+{
+    write_data_t *w = (write_data_t *)task;
+    write_data( w->hdr.request, w->buffer, w->to_write, w->written, TRUE );
+}
+
 /***********************************************************************
  *          WinHttpWriteData (winhttp.@)
  */
 BOOL WINAPI WinHttpWriteData( HINTERNET hrequest, LPCVOID buffer, DWORD to_write, LPDWORD written )
 {
     BOOL ret;
-    int num_bytes;
     request_t *request;
 
     TRACE("%p, %p, %d, %p\n", hrequest, buffer, to_write, written);
@@ -1354,20 +1506,23 @@ BOOL WINAPI WinHttpWriteData( HINTERNET hrequest, LPCVOID buffer, DWORD to_write
         return FALSE;
     }
 
-    ret = netconn_send( &request->netconn, buffer, to_write, 0, &num_bytes );
-
     if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC)
     {
-        if (ret) send_callback( &request->hdr, WINHTTP_CALLBACK_FLAG_WRITE_COMPLETE, &num_bytes, sizeof(DWORD) );
-        else
-        {
-            WINHTTP_ASYNC_RESULT async;
-            async.dwResult = API_WRITE_DATA;
-            async.dwError  = get_last_error();
-            send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &async, sizeof(async) );
-        }
+        write_data_t *w;
+
+        if (!(w = heap_alloc( sizeof(write_data_t) ))) return FALSE;
+        w->hdr.request = request;
+        w->hdr.proc    = task_write_data;
+        w->buffer      = buffer;
+        w->to_write    = to_write;
+        w->written     = written;
+
+        addref_object( &request->hdr );
+        ret = queue_task( (task_header_t *)w );
     }
-    if (ret && written) *written = num_bytes;
+    else
+        ret = write_data( request, buffer, to_write, written, FALSE );
+
     release_object( &request->hdr );
     return ret;
 }
diff --git a/dlls/winhttp/tests/notification.c b/dlls/winhttp/tests/notification.c
index 8b11e06..784e350 100644
--- a/dlls/winhttp/tests/notification.c
+++ b/dlls/winhttp/tests/notification.c
@@ -34,6 +34,9 @@ enum api
     winhttp_open_request,
     winhttp_send_request,
     winhttp_receive_response,
+    winhttp_query_data,
+    winhttp_read_data,
+    winhttp_write_data,
     winhttp_close_handle
 };
 
@@ -70,12 +73,15 @@ static void CALLBACK check_notification( HINTERNET handle, DWORD_PTR context, DW
         ok(info->test[i].status == status, "expected status 0x%08x got 0x%08x\n", info->test[i].status, status);
         ok(info->test[i].function == info->function, "expected function %u got %u\n", info->test[i].function, info->function);
     }
-    else todo_wine
+    else
     {
-        ok(info->test[i].status == status, "expected status 0x%08x got 0x%08x\n", info->test[i].status, status);
-        ok(info->test[i].function == info->function, "expected function %u got %u\n", info->test[i].function, info->function);
+        todo_wine ok(info->test[i].status == status, "expected status 0x%08x got 0x%08x\n", info->test[i].status, status);
+        if (info->test[i].status == status)
+        {
+            todo_wine ok(info->test[i].function == info->function, "expected function %u got %u\n", info->test[i].function, info->function);
+        }
     }
-    info->index++;
+    if (info->test[i].status == status) info->index++;
     if (status & WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS) SetEvent( info->wait );
 }
 
@@ -146,7 +152,7 @@ static void test_connection_cache( void )
     WinHttpCloseHandle( con );
     WinHttpCloseHandle( ses );
 
-    Sleep(2000); /* make sure connection is evicted from cache */
+    Sleep(1500); /* make sure connection is evicted from cache */
 
     info.index = 0;
 
@@ -287,6 +293,10 @@ static const struct notification async_test[] =
     { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, 0 },
     { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, 0 },
     { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, 0 },
+    { winhttp_query_data,       WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE, 0 },
+    { winhttp_read_data,        WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, 1 },
+    { winhttp_read_data,        WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, 1 },
+    { winhttp_read_data,        WINHTTP_CALLBACK_STATUS_READ_COMPLETE, 1 },
     { winhttp_close_handle,     WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, 0 },
     { winhttp_close_handle,     WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, 0 },
     { winhttp_close_handle,     WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, 0 },
@@ -302,6 +312,7 @@ static void test_async( void )
     DWORD size, status;
     BOOL ret;
     struct info info, *context = &info;
+    char buffer[1024];
 
     info.test  = async_test;
     info.count = sizeof(async_test) / sizeof(async_test[0]);
@@ -341,6 +352,18 @@ static void test_async( void )
     ok(ret, "failed unexpectedly %u\n", GetLastError());
     ok(status == 200, "request failed unexpectedly %u\n", status);
 
+    info.function = winhttp_query_data;
+    ret = WinHttpQueryDataAvailable( req, NULL );
+    ok(ret, "failed to query data available %u\n", GetLastError());
+
+    WaitForSingleObject( info.wait, INFINITE );
+
+    info.function = winhttp_read_data;
+    ret = WinHttpReadData( req, buffer, sizeof(buffer), NULL );
+    ok(ret, "failed to query data available %u\n", GetLastError());
+
+    WaitForSingleObject( info.wait, INFINITE );
+
     info.function = winhttp_close_handle;
     WinHttpCloseHandle( req );
     WinHttpCloseHandle( con );
@@ -352,5 +375,6 @@ START_TEST (notification)
 {
     test_connection_cache();
     test_redirect();
+    Sleep(1500); /* make sure previous connection is evicted from cache */
     test_async();
 }
diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h
index 6d9a142..6508b38 100644
--- a/dlls/winhttp/winhttp_private.h
+++ b/dlls/winhttp/winhttp_private.h
@@ -120,6 +120,52 @@ typedef struct
     DWORD num_headers;
 } request_t;
 
+typedef struct _task_header_t task_header_t;
+
+struct _task_header_t
+{
+    request_t *request;
+    void (*proc)( task_header_t * );
+};
+
+typedef struct
+{
+    task_header_t hdr;
+    LPWSTR headers;
+    DWORD headers_len;
+    LPVOID optional;
+    DWORD optional_len;
+    DWORD total_len;
+    DWORD_PTR context;
+} send_request_t;
+
+typedef struct
+{
+    task_header_t hdr;
+} receive_response_t;
+
+typedef struct
+{
+    task_header_t hdr;
+    LPDWORD available;
+} query_data_t;
+
+typedef struct
+{
+    task_header_t hdr;
+    LPVOID buffer;
+    DWORD to_read;
+    LPDWORD read;
+} read_data_t;
+
+typedef struct
+{
+    task_header_t hdr;
+    LPCVOID buffer;
+    DWORD to_write;
+    LPDWORD written;
+} write_data_t;
+
 object_header_t *addref_object( object_header_t * );
 object_header_t *grab_object( HINTERNET );
 void release_object( object_header_t * );



More information about the wine-patches mailing list