[6/6] webservices: Implement WsCall.

Hans Leidekker hans at codeweavers.com
Tue Oct 25 06:03:23 CDT 2016


Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
 dlls/webservices/msg.c                 |  78 ++++++++++---
 dlls/webservices/proxy.c               | 154 +++++++++++++++++++++++-
 dlls/webservices/reader.c              | 104 +++++++++++++++++
 dlls/webservices/tests/proxy.c         | 208 +++++++++++++++++++++++++++++++++
 dlls/webservices/webservices_private.h |  11 ++
 dlls/webservices/writer.c              |  42 ++++++-
 6 files changed, 575 insertions(+), 22 deletions(-)

diff --git a/dlls/webservices/msg.c b/dlls/webservices/msg.c
index 8f44b40..e7a7969 100644
--- a/dlls/webservices/msg.c
+++ b/dlls/webservices/msg.c
@@ -64,24 +64,26 @@ struct header
 
 struct msg
 {
-    WS_MESSAGE_INITIALIZATION init;
-    WS_MESSAGE_STATE          state;
-    GUID                      id;
-    WS_ENVELOPE_VERSION       version_env;
-    WS_ADDRESSING_VERSION     version_addr;
-    BOOL                      is_addressed;
-    WS_STRING                 addr;
-    WS_STRING                 action;
-    WS_HEAP                  *heap;
-    WS_XML_BUFFER            *buf;
-    WS_XML_WRITER            *writer;
-    WS_XML_WRITER            *writer_body;
-    WS_XML_READER            *reader_body;
-    ULONG                     header_count;
-    ULONG                     header_size;
-    struct header           **header;
-    ULONG                     prop_count;
-    struct prop               prop[sizeof(msg_props)/sizeof(msg_props[0])];
+    WS_MESSAGE_INITIALIZATION           init;
+    WS_MESSAGE_STATE                    state;
+    GUID                                id;
+    WS_ENVELOPE_VERSION                 version_env;
+    WS_ADDRESSING_VERSION               version_addr;
+    BOOL                                is_addressed;
+    WS_STRING                           addr;
+    WS_STRING                           action;
+    WS_HEAP                            *heap;
+    WS_XML_BUFFER                      *buf;
+    WS_XML_WRITER                      *writer;
+    WS_XML_WRITER                      *writer_body;
+    WS_XML_READER                      *reader_body;
+    ULONG                               header_count;
+    ULONG                               header_size;
+    struct header                     **header;
+    WS_PROXY_MESSAGE_CALLBACK_CONTEXT   ctx_send;
+    WS_PROXY_MESSAGE_CALLBACK_CONTEXT   ctx_receive;
+    ULONG                               prop_count;
+    struct prop                         prop[sizeof(msg_props)/sizeof(msg_props[0])];
 };
 
 #define HEADER_ARRAY_SIZE 2
@@ -953,7 +955,7 @@ static HRESULT build_mapped_header( const WS_XML_STRING *name, WS_TYPE type, WS_
  *          WsAddMappedHeader		[webservices.@]
  */
 HRESULT WINAPI WsAddMappedHeader( WS_MESSAGE *handle, const WS_XML_STRING *name, WS_TYPE type,
-                                  WS_WRITE_OPTION option, const void *value, ULONG size , WS_ERROR *error )
+                                  WS_WRITE_OPTION option, const void *value, ULONG size, WS_ERROR *error )
 {
     struct msg *msg = (struct msg *)handle;
     struct header *header;
@@ -1209,6 +1211,44 @@ HRESULT message_insert_http_headers( WS_MESSAGE *handle, HINTERNET req )
     return S_OK;
 }
 
+void message_set_send_context( WS_MESSAGE *handle, const WS_PROXY_MESSAGE_CALLBACK_CONTEXT *ctx )
+{
+    struct msg *msg = (struct msg *)handle;
+    msg->ctx_send.callback = ctx->callback;
+    msg->ctx_send.state    = ctx->state;
+}
+
+void message_set_receive_context( WS_MESSAGE *handle, const WS_PROXY_MESSAGE_CALLBACK_CONTEXT *ctx )
+{
+    struct msg *msg = (struct msg *)handle;
+    msg->ctx_receive.callback = ctx->callback;
+    msg->ctx_receive.state    = ctx->state;
+}
+
+void message_do_send_callback( WS_MESSAGE *handle )
+{
+    struct msg *msg = (struct msg *)handle;
+    if (msg->ctx_send.callback)
+    {
+        HRESULT hr;
+        TRACE( "executing callback %p\n", msg->ctx_send.callback );
+        hr = msg->ctx_send.callback( handle, msg->heap, msg->ctx_send.state, NULL );
+        TRACE( "callback %p returned %08x\n", msg->ctx_send.callback, hr );
+    }
+}
+
+void message_do_receive_callback( WS_MESSAGE *handle )
+{
+    struct msg *msg = (struct msg *)handle;
+    if (msg->ctx_receive.callback)
+    {
+        HRESULT hr;
+        TRACE( "executing callback %p\n", msg->ctx_receive.callback );
+        hr = msg->ctx_receive.callback( handle, msg->heap, msg->ctx_receive.state, NULL );
+        TRACE( "callback %p returned %08x\n", msg->ctx_receive.callback, hr );
+    }
+}
+
 HRESULT message_set_action( WS_MESSAGE *handle, const WS_XML_STRING *action )
 {
     struct msg *msg = (struct msg *)handle;
diff --git a/dlls/webservices/proxy.c b/dlls/webservices/proxy.c
index 96ac1ad..05214e0 100644
--- a/dlls/webservices/proxy.c
+++ b/dlls/webservices/proxy.c
@@ -245,6 +245,127 @@ HRESULT WINAPI WsAbortServiceProxy( WS_SERVICE_PROXY *handle, WS_ERROR *error )
     return E_NOTIMPL;
 }
 
+static HRESULT set_send_context( WS_MESSAGE *msg, const WS_CALL_PROPERTY *props, ULONG count )
+{
+    ULONG i;
+    for (i = 0; i < count; i++)
+    {
+        if (props[i].id == WS_CALL_PROPERTY_SEND_MESSAGE_CONTEXT)
+        {
+            if (props[i].valueSize != sizeof(WS_PROXY_MESSAGE_CALLBACK_CONTEXT)) return E_INVALIDARG;
+            message_set_send_context( msg, props[i].value );
+            break;
+        }
+    }
+    return S_OK;
+}
+
+static HRESULT set_receive_context( WS_MESSAGE *msg, const WS_CALL_PROPERTY *props, ULONG count )
+{
+    ULONG i;
+    for (i = 0; i < count; i++)
+    {
+        if (props[i].id == WS_CALL_PROPERTY_RECEIVE_MESSAGE_CONTEXT)
+        {
+            if (props[i].valueSize != sizeof(WS_PROXY_MESSAGE_CALLBACK_CONTEXT)) return E_INVALIDARG;
+            message_set_receive_context( msg, props[i].value );
+            break;
+        }
+    }
+    return S_OK;
+}
+
+static HRESULT write_message( WS_MESSAGE *msg, WS_XML_WRITER *writer, const WS_ELEMENT_DESCRIPTION *desc,
+                              const WS_PARAMETER_DESCRIPTION *params, ULONG count, const void **args )
+{
+    HRESULT hr;
+    message_do_send_callback( msg );
+    if ((hr = WsWriteEnvelopeStart( msg, writer, NULL, NULL, NULL )) != S_OK) return hr;
+    if ((hr = write_input_params( writer, desc, params, count, args )) != S_OK) return hr;
+    return WsWriteEnvelopeEnd( msg, NULL );
+}
+
+static HRESULT send_message( WS_CHANNEL *channel, WS_MESSAGE *msg, WS_MESSAGE_DESCRIPTION *desc,
+                             WS_PARAMETER_DESCRIPTION *params, ULONG count, const void **args )
+{
+    WS_XML_WRITER *writer;
+    HRESULT hr;
+
+    if ((hr = message_set_action( msg, desc->action )) != S_OK) return hr;
+    if ((hr = WsCreateWriter( NULL, 0, &writer, NULL )) != S_OK) return hr;
+    if ((hr = set_output( writer )) != S_OK) goto done;
+    if ((hr = write_message( msg, writer, desc->bodyElementDescription, params, count, args )) != S_OK) goto done;
+    hr = channel_send_message( channel, msg );
+
+done:
+    WsFreeWriter( writer );
+    return hr;
+}
+
+static HRESULT read_message( WS_MESSAGE *msg, WS_XML_READER *reader, WS_HEAP *heap,
+                             const WS_ELEMENT_DESCRIPTION *desc, const WS_PARAMETER_DESCRIPTION *params,
+                             ULONG count, const void **args )
+{
+    HRESULT hr;
+    if ((hr = WsReadEnvelopeStart( msg, reader, NULL, NULL, NULL )) != S_OK) return hr;
+    message_do_receive_callback( msg );
+    if ((hr = read_output_params( reader, heap, desc, params, count, args )) != S_OK) return hr;
+    return WsReadEnvelopeEnd( msg, NULL );
+}
+
+static HRESULT receive_message( WS_CHANNEL *channel, WS_MESSAGE *msg, WS_MESSAGE_DESCRIPTION *desc,
+                                WS_PARAMETER_DESCRIPTION *params, ULONG count, WS_HEAP *heap, const void **args )
+{
+    WS_XML_READER *reader;
+    char *buf;
+    ULONG len;
+    HRESULT hr;
+
+    if ((hr = message_set_action( msg, desc->action )) != S_OK) return hr;
+    if ((hr = channel_receive_message( channel, &buf, &len )) != S_OK) return hr;
+    if ((hr = WsCreateReader( NULL, 0, &reader, NULL )) != S_OK) goto done;
+    if ((hr = set_input( reader, buf, len )) != S_OK) goto done;
+    hr = read_message( msg, reader, heap, desc->bodyElementDescription, params, count, args );
+
+done:
+    WsFreeReader( reader );
+    heap_free( buf);
+    return hr;
+}
+
+static HRESULT create_input_message( WS_CHANNEL *channel, const WS_CALL_PROPERTY *properties,
+                                     ULONG count, WS_MESSAGE **ret )
+{
+    WS_MESSAGE *msg;
+    HRESULT hr;
+
+    if ((hr = WsCreateMessageForChannel( channel, NULL, 0, &msg, NULL )) != S_OK) return hr;
+    if ((hr = WsInitializeMessage( msg, WS_REQUEST_MESSAGE, NULL, NULL )) != S_OK ||
+        (hr = set_send_context( msg, properties, count )) != S_OK)
+    {
+        WsFreeMessage( msg );
+        return hr;
+    }
+    *ret = msg;
+    return S_OK;
+}
+
+static HRESULT create_output_message( WS_CHANNEL *channel, const WS_CALL_PROPERTY *properties,
+                                      ULONG count, WS_MESSAGE **ret )
+{
+    WS_MESSAGE *msg;
+    HRESULT hr;
+
+    if ((hr = WsCreateMessageForChannel( channel, NULL, 0, &msg, NULL )) != S_OK) return hr;
+    if ((hr = set_receive_context( msg, properties, count )) != S_OK)
+    {
+        WsFreeMessage( msg );
+        return hr;
+    }
+    *ret = msg;
+    return S_OK;
+}
+
 /**************************************************************************
  *          WsCall		[webservices.@]
  */
@@ -252,6 +373,35 @@ HRESULT WINAPI WsCall( WS_SERVICE_PROXY *handle, const WS_OPERATION_DESCRIPTION
                        WS_HEAP *heap, const WS_CALL_PROPERTY *properties, const ULONG count,
                        const WS_ASYNC_CONTEXT *ctx, WS_ERROR *error )
 {
-    FIXME( "%p %p %p %p %p %u %p %p\n", handle, desc, args, heap, properties, count, ctx, error );
-    return E_NOTIMPL;
+    struct proxy *proxy = (struct proxy *)handle;
+    WS_MESSAGE *msg;
+    HRESULT hr;
+    ULONG i;
+
+    TRACE( "%p %p %p %p %p %u %p %p\n", handle, desc, args, heap, properties, count, ctx, error );
+    if (error) FIXME( "ignoring error parameter\n" );
+    if (ctx) FIXME( "ignoring ctx parameter\n" );
+    for (i = 0; i < count; i++)
+    {
+        if (properties[i].id != WS_CALL_PROPERTY_SEND_MESSAGE_CONTEXT &&
+            properties[i].id != WS_CALL_PROPERTY_RECEIVE_MESSAGE_CONTEXT)
+        {
+            FIXME( "unimplemented call property %u\n", properties[i].id );
+            return E_NOTIMPL;
+        }
+    }
+
+    if (!handle || !desc || (desc->parameterCount && !args)) return E_INVALIDARG;
+
+    if ((hr = create_input_message( proxy->channel, properties, count, &msg )) != S_OK) return hr;
+    hr = send_message( proxy->channel, msg, desc->inputMessageDescription, desc->parameterDescription,
+                       desc->parameterCount, args );
+    WsFreeMessage( msg );
+    if (hr != S_OK) return hr;
+
+    if ((hr = create_output_message( proxy->channel, properties, count, &msg )) != S_OK) return hr;
+    hr = receive_message( proxy->channel, msg, desc->outputMessageDescription, desc->parameterDescription,
+                          desc->parameterCount, heap, args );
+    WsFreeMessage( msg );
+    return hr;
 }
diff --git a/dlls/webservices/reader.c b/dlls/webservices/reader.c
index 9994798..5b5dc69 100644
--- a/dlls/webservices/reader.c
+++ b/dlls/webservices/reader.c
@@ -4665,3 +4665,107 @@ HRESULT WINAPI WsReadCharsUtf8( WS_XML_READER *handle, BYTE *bytes, ULONG max_co
 
     return S_OK;
 }
+
+HRESULT get_param_desc( const WS_STRUCT_DESCRIPTION *desc, USHORT index, const WS_FIELD_DESCRIPTION **ret )
+{
+    if (index >= desc->fieldCount) return E_INVALIDARG;
+    *ret = desc->fields[index];
+    return S_OK;
+}
+
+static ULONG get_field_size( const WS_FIELD_DESCRIPTION *desc )
+{
+    WS_READ_OPTION option;
+    ULONG size;
+
+    switch ((option = get_field_read_option( desc->type, desc->options )))
+    {
+    case WS_READ_REQUIRED_POINTER:
+    case WS_READ_OPTIONAL_POINTER:
+    case WS_READ_NILLABLE_POINTER:
+        size = sizeof(void *);
+        break;
+
+    case WS_READ_REQUIRED_VALUE:
+    case WS_READ_NILLABLE_VALUE:
+        size = get_type_size( desc->type, desc->typeDescription );
+        break;
+
+    default:
+        WARN( "unhandled option %u\n", option );
+        return 0;
+    }
+
+    return size;
+}
+
+static HRESULT read_param( struct reader *reader, const WS_FIELD_DESCRIPTION *desc, WS_HEAP *heap, void *ret )
+{
+    if (!ret && !(ret = ws_alloc_zero( heap, get_field_size(desc) ))) return WS_E_QUOTA_EXCEEDED;
+    return read_type_struct_field( reader, desc, heap, ret, 0 );
+}
+
+static HRESULT read_param_array( struct reader *reader, const WS_FIELD_DESCRIPTION *desc, WS_HEAP *heap,
+                                 void **ret, ULONG *count )
+{
+    if (!ret && !(ret = ws_alloc_zero( heap, sizeof(void **) ))) return WS_E_QUOTA_EXCEEDED;
+    return read_type_repeating_element( reader, desc, heap, ret, count );
+}
+
+static void set_array_len( const WS_PARAMETER_DESCRIPTION *params, ULONG count, ULONG index, ULONG len,
+                           const void **args )
+{
+    ULONG i, *ptr;
+    for (i = 0; i < count; i++)
+    {
+        if (params[i].outputMessageIndex != index || params[i].parameterType != WS_PARAMETER_TYPE_ARRAY_COUNT)
+            continue;
+        if ((ptr = *(ULONG **)args[i])) *ptr = len;
+        break;
+    }
+}
+
+HRESULT read_output_params( WS_XML_READER *handle, WS_HEAP *heap, const WS_ELEMENT_DESCRIPTION *desc,
+                            const WS_PARAMETER_DESCRIPTION *params, ULONG count, const void **args )
+{
+    struct reader *reader = (struct reader *)handle;
+    const WS_STRUCT_DESCRIPTION *desc_struct;
+    const WS_FIELD_DESCRIPTION *desc_field;
+    ULONG i, len;
+    HRESULT hr;
+
+    if (desc->type != WS_STRUCT_TYPE || !(desc_struct = desc->typeDescription)) return E_INVALIDARG;
+
+    if ((hr = start_mapping( reader, WS_ELEMENT_TYPE_MAPPING, desc->elementLocalName, desc->elementNs )) != S_OK)
+        return hr;
+
+    for (i = 0; i < count; i++)
+    {
+        if (params[i].outputMessageIndex == INVALID_PARAMETER_INDEX) continue;
+        if (params[i].parameterType == WS_PARAMETER_TYPE_MESSAGES)
+        {
+            FIXME( "messages type not supported\n" );
+            return E_NOTIMPL;
+        }
+        if ((hr = get_param_desc( desc_struct, params[i].outputMessageIndex, &desc_field )) != S_OK) return hr;
+        if (params[i].parameterType == WS_PARAMETER_TYPE_NORMAL)
+        {
+            void *ptr = *(void **)args[i];
+            if ((hr = read_param( reader, desc_field, heap, ptr )) != S_OK) return hr;
+        }
+        else if (params[i].parameterType == WS_PARAMETER_TYPE_ARRAY)
+        {
+            void **ptr = *(void ***)args[i];
+            if ((hr = read_param_array( reader, desc_field, heap, ptr, &len )) != S_OK) return hr;
+            set_array_len( params, count, params[i].outputMessageIndex, len, args );
+        }
+    }
+
+    if (desc_struct->structOptions & WS_STRUCT_IGNORE_TRAILING_ELEMENT_CONTENT)
+    {
+        struct node *parent = find_parent( reader );
+        parent->flags |= NODE_FLAG_IGNORE_TRAILING_ELEMENT_CONTENT;
+    }
+
+    return end_mapping( reader, WS_ELEMENT_TYPE_MAPPING );
+}
diff --git a/dlls/webservices/tests/proxy.c b/dlls/webservices/tests/proxy.c
index fa4348a..f1676cd 100644
--- a/dlls/webservices/tests/proxy.c
+++ b/dlls/webservices/tests/proxy.c
@@ -249,6 +249,211 @@ static void test_WsReceiveMessage( int port )
     WsFreeMessage( msg );
 }
 
+static HRESULT create_proxy( int port, WS_SERVICE_PROXY **ret )
+{
+    static const WCHAR fmt[] =
+        {'h','t','t','p',':','/','/','1','2','7','.','0','.','0','.','1',':','%','u','/',0};
+    WS_ENVELOPE_VERSION env_version;
+    WS_ADDRESSING_VERSION addr_version;
+    WS_CHANNEL_PROPERTY prop[2];
+    WS_ENDPOINT_ADDRESS addr;
+    WS_SERVICE_PROXY *proxy;
+    WCHAR url[64];
+    HRESULT hr;
+
+    env_version = WS_ENVELOPE_VERSION_SOAP_1_1;
+    prop[0].id        = WS_CHANNEL_PROPERTY_ENVELOPE_VERSION;
+    prop[0].value     = &env_version;
+    prop[0].valueSize = sizeof(env_version);
+
+    addr_version = WS_ADDRESSING_VERSION_TRANSPORT;
+    prop[1].id        = WS_CHANNEL_PROPERTY_ADDRESSING_VERSION;
+    prop[1].value     = &addr_version;
+    prop[1].valueSize = sizeof(addr_version);
+
+    *ret = NULL;
+    hr = WsCreateServiceProxy( WS_CHANNEL_TYPE_REQUEST, WS_HTTP_CHANNEL_BINDING, NULL, NULL,
+                               0, prop, sizeof(prop)/sizeof(prop[0]), &proxy, NULL );
+    if (hr != S_OK) return hr;
+
+    addr.url.length = wsprintfW( url, fmt, port );
+    addr.url.chars  = url;
+    addr.headers    = NULL;
+    addr.extensions = NULL;
+    addr.identity   = NULL;
+    hr = WsOpenServiceProxy( proxy, &addr, NULL, NULL );
+    if (hr == S_OK) *ret = proxy;
+    else WsFreeServiceProxy( proxy );
+    return hr;
+}
+
+static const char req_test2[] =
+    "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"><s:Body>"
+    "<req_test2 xmlns=\"ns\"><val>1</val></req_test2>"
+    "</s:Body></s:Envelope>";
+
+static const char resp_test2[] =
+    "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"><s:Body>"
+    "<resp_test2 xmlns=\"ns\"><str>test</str><val>1</val><val>2</val></resp_test2>"
+    "</s:Body></s:Envelope>";
+
+static void test_WsCall( int port )
+{
+    static WCHAR testW[] = {'t','e','s','t',0};
+    WS_XML_STRING str = {3, (BYTE *)"str"};
+    WS_XML_STRING req = {3, (BYTE *)"req"};
+    WS_XML_STRING resp = {4, (BYTE *)"resp"};
+    WS_XML_STRING req_elem = {9, (BYTE *)"req_test2"};
+    WS_XML_STRING resp_elem = {10, (BYTE *)"resp_test2"};
+    WS_XML_STRING req_action = {9, (BYTE *)"req_test2"};
+    WS_XML_STRING resp_action = {10, (BYTE *)"resp_test2"};
+    WS_XML_STRING val = {3, (BYTE *)"val"};
+    WS_XML_STRING ns = {2, (BYTE *)"ns"};
+    HRESULT hr;
+    WS_SERVICE_PROXY *proxy;
+    WS_OPERATION_DESCRIPTION op;
+    WS_MESSAGE_DESCRIPTION input_msg, output_msg;
+    WS_ELEMENT_DESCRIPTION input_elem, output_elem;
+    WS_STRUCT_DESCRIPTION input_struct, output_struct;
+    WS_FIELD_DESCRIPTION f, f2, f3, *fields[2], *fields2[2];
+    WS_PARAMETER_DESCRIPTION param[4];
+    const void *args[4];
+    WS_HEAP *heap;
+    INT32 **val_ptr;
+    WCHAR **str_ptr;
+    ULONG *count_ptr;
+    struct input
+    {
+        INT32   val;
+    } in;
+    struct output
+    {
+        WCHAR *str;
+        ULONG  count;
+        INT32 *val;
+    } out;
+
+    hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    hr = WsCall( NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL );
+    ok( hr == E_INVALIDARG, "got %08x\n", hr );
+
+    hr = create_proxy( port, &proxy );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    hr = WsCall( proxy, NULL, NULL, NULL, NULL, 0, NULL, NULL );
+    ok( hr == E_INVALIDARG, "got %08x\n", hr );
+
+    memset( &f, 0, sizeof(f) );
+    f.mapping   = WS_ELEMENT_FIELD_MAPPING;
+    f.localName = &val;
+    f.ns        = &ns;
+    f.type      = WS_INT32_TYPE;
+    fields[0] = &f;
+
+    memset( &input_struct, 0, sizeof(input_struct) );
+    input_struct.size          = sizeof(struct input);
+    input_struct.alignment     = TYPE_ALIGNMENT(struct input);
+    input_struct.fields        = fields;
+    input_struct.fieldCount    = 1;
+    input_struct.typeLocalName = &req;
+    input_struct.typeNs        = &ns;
+
+    input_elem.elementLocalName = &req_elem;
+    input_elem.elementNs        = &ns;
+    input_elem.type             = WS_STRUCT_TYPE;
+    input_elem.typeDescription  = &input_struct;
+    input_msg.action                 = &req_action;
+    input_msg.bodyElementDescription = &input_elem;
+
+    memset( &f2, 0, sizeof(f2) );
+    f2.mapping       = WS_ELEMENT_FIELD_MAPPING;
+    f2.localName     = &str;
+    f2.ns            = &ns;
+    f2.type          = WS_WSZ_TYPE;
+    f2.offset        = FIELD_OFFSET(struct output, str);
+    fields2[0] = &f2;
+
+    memset( &f3, 0, sizeof(f3) );
+    f3.mapping       = WS_REPEATING_ELEMENT_FIELD_MAPPING;
+    f3.type          = WS_INT32_TYPE;
+    f3.offset        = FIELD_OFFSET(struct output, val);
+    f3.countOffset   = FIELD_OFFSET(struct output, count);
+    f3.itemLocalName = &val;
+    f3.itemNs        = &ns;
+    fields2[1] = &f3;
+
+    memset( &output_struct, 0, sizeof(output_struct) );
+    output_struct.size          = sizeof(struct output);
+    output_struct.alignment     = TYPE_ALIGNMENT(struct output);
+    output_struct.fields        = fields2;
+    output_struct.fieldCount    = 2;
+    output_struct.typeLocalName = &resp;
+    output_struct.typeNs        = &ns;
+
+    output_elem.elementLocalName = &resp_elem;
+    output_elem.elementNs        = &ns;
+    output_elem.type             = WS_STRUCT_TYPE;
+    output_elem.typeDescription  = &output_struct;
+    output_msg.action                 = &resp_action;
+    output_msg.bodyElementDescription = &output_elem;
+
+    param[0].parameterType      = WS_PARAMETER_TYPE_NORMAL;
+    param[0].inputMessageIndex  = 0;
+    param[0].outputMessageIndex = 0xffff;
+
+    param[1].parameterType      = WS_PARAMETER_TYPE_NORMAL;
+    param[1].inputMessageIndex  = 0xffff;
+    param[1].outputMessageIndex = 0;
+
+    param[2].parameterType      = WS_PARAMETER_TYPE_ARRAY;
+    param[2].inputMessageIndex  = 0xffff;
+    param[2].outputMessageIndex = 1;
+
+    param[3].parameterType      = WS_PARAMETER_TYPE_ARRAY_COUNT;
+    param[3].inputMessageIndex  = 0xffff;
+    param[3].outputMessageIndex = 1;
+
+    op.versionInfo              = 1;
+    op.inputMessageDescription  = &input_msg;
+    op.outputMessageDescription = &output_msg;
+    op.inputMessageOptions      = 0;
+    op.outputMessageOptions     = 0;
+    op.parameterCount           = 4;
+    op.parameterDescription     = param;
+    op.stubCallback             = NULL;
+    op.style                    = 0;
+    hr = WsCall( proxy, &op, NULL, NULL, NULL, 0, NULL, NULL );
+    ok( hr == E_INVALIDARG, "got %08x\n", hr );
+
+    in.val   = 1;
+    args[0] = &in.val;
+
+    out.str   = NULL;
+    out.count = 0;
+    out.val   = 0;
+    str_ptr   = &out.str;
+    val_ptr   = &out.val;
+    count_ptr = &out.count;
+    args[1] = &str_ptr;
+    args[2] = &val_ptr;
+    args[3] = &count_ptr;
+
+    hr = WsCall( proxy, &op, args, heap, NULL, 0, NULL, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+    ok( !lstrcmpW( out.str, testW ), "wrong data\n" );
+    ok( out.count == 2, "got %u\n", out.count );
+    ok( out.val[0] == 1, "got %u\n", out.val[0] );
+    ok( out.val[1] == 2, "got %u\n", out.val[1] );
+
+    hr = WsCloseServiceProxy( proxy, NULL, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    WsFreeServiceProxy( proxy );
+    WsFreeHeap( heap );
+}
+
 static const struct
 {
     const char   *req_action;
@@ -261,6 +466,7 @@ static const struct
 tests[] =
 {
     { "req_test1", req_test1, sizeof(req_test1)-1, "resp_test1", resp_test1, sizeof(resp_test1)-1 },
+    { "req_test2", req_test2, sizeof(req_test2)-1, "resp_test2", resp_test2, sizeof(resp_test2)-1 },
 };
 
 static void send_response( int c, const char *action, const char *data, unsigned int len )
@@ -349,6 +555,7 @@ static DWORD CALLBACK server_proc( void *arg )
                         ok( !memcmp( tests[j].req_data, buf, tests[j].req_len ), "%u: unexpected data\n", j );
                 }
                 send_response( c, tests[j].resp_action, tests[j].resp_data, tests[j].resp_len );
+                break;
             }
         }
 
@@ -383,6 +590,7 @@ START_TEST(proxy)
 
     test_WsSendMessage( info.port, &test1 );
     test_WsReceiveMessage( info.port );
+    test_WsCall( info.port );
 
     test_WsSendMessage( info.port, &quit );
     WaitForSingleObject( thread, 3000 );
diff --git a/dlls/webservices/webservices_private.h b/dlls/webservices/webservices_private.h
index 424f3fe..b442838 100644
--- a/dlls/webservices/webservices_private.h
+++ b/dlls/webservices/webservices_private.h
@@ -41,6 +41,13 @@ HRESULT set_output( WS_XML_WRITER * ) DECLSPEC_HIDDEN;
 HRESULT set_input( WS_XML_READER *, char *, ULONG ) DECLSPEC_HIDDEN;
 ULONG get_type_size( WS_TYPE, const WS_STRUCT_DESCRIPTION * ) DECLSPEC_HIDDEN;
 
+#define INVALID_PARAMETER_INDEX 0xffff
+HRESULT get_param_desc( const WS_STRUCT_DESCRIPTION *, USHORT, const WS_FIELD_DESCRIPTION ** ) DECLSPEC_HIDDEN;
+HRESULT write_input_params( WS_XML_WRITER *, const WS_ELEMENT_DESCRIPTION *,
+                            const WS_PARAMETER_DESCRIPTION *, ULONG, const void ** ) DECLSPEC_HIDDEN;
+HRESULT read_output_params( WS_XML_READER *, WS_HEAP *, const WS_ELEMENT_DESCRIPTION *,
+                            const WS_PARAMETER_DESCRIPTION *, ULONG, const void ** ) DECLSPEC_HIDDEN;
+
 enum node_flag
 {
     NODE_FLAG_IGNORE_TRAILING_ELEMENT_CONTENT   = 0x1,
@@ -100,6 +107,10 @@ HRESULT prop_set( const struct prop *, ULONG, ULONG, const void *, ULONG ) DECLS
 HRESULT prop_get( const struct prop *, ULONG, ULONG, void *, ULONG ) DECLSPEC_HIDDEN;
 
 HRESULT message_set_action( WS_MESSAGE *, const WS_XML_STRING * ) DECLSPEC_HIDDEN;
+void message_set_send_context( WS_MESSAGE *, const WS_PROXY_MESSAGE_CALLBACK_CONTEXT * ) DECLSPEC_HIDDEN;
+void message_set_receive_context( WS_MESSAGE *, const WS_PROXY_MESSAGE_CALLBACK_CONTEXT * ) DECLSPEC_HIDDEN;
+void message_do_send_callback( WS_MESSAGE * ) DECLSPEC_HIDDEN;
+void message_do_receive_callback( WS_MESSAGE * ) DECLSPEC_HIDDEN;
 HRESULT message_insert_http_headers( WS_MESSAGE *, HINTERNET ) DECLSPEC_HIDDEN;
 
 HRESULT channel_send_message( WS_CHANNEL *, WS_MESSAGE * ) DECLSPEC_HIDDEN;
diff --git a/dlls/webservices/writer.c b/dlls/webservices/writer.c
index 4622277..7982cef 100644
--- a/dlls/webservices/writer.c
+++ b/dlls/webservices/writer.c
@@ -2107,7 +2107,7 @@ static HRESULT write_type_struct( struct writer *writer, WS_TYPE_MAPPING mapping
     if (!desc) return E_INVALIDARG;
     if (desc->structOptions) FIXME( "struct options 0x%x not supported\n", desc->structOptions );
 
-    if ((hr = get_value_ptr( option, value, size, desc->size, (const void **)&ptr )) != S_OK) return hr;
+    if ((hr = get_value_ptr( option, value, size, desc->size, &ptr )) != S_OK) return hr;
 
     for (i = 0; i < desc->fieldCount; i++)
     {
@@ -2792,3 +2792,43 @@ HRESULT WINAPI WsCopyNode( WS_XML_WRITER *handle, WS_XML_READER *reader, WS_ERRO
     writer->current = current;
     return S_OK;
 }
+
+static HRESULT write_param( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const void *value )
+{
+    return write_type_struct_field( writer, desc, value, get_field_size(desc) );
+}
+
+HRESULT write_input_params( WS_XML_WRITER *handle, const WS_ELEMENT_DESCRIPTION *desc,
+                            const WS_PARAMETER_DESCRIPTION *params, ULONG count, const void **args )
+{
+    struct writer *writer = (struct writer *)handle;
+    const WS_STRUCT_DESCRIPTION *desc_struct;
+    const WS_FIELD_DESCRIPTION *desc_field;
+    HRESULT hr;
+    ULONG i;
+
+    if (desc->type != WS_STRUCT_TYPE || !(desc_struct = desc->typeDescription)) return E_INVALIDARG;
+
+    if ((hr = write_element_node( writer, NULL, desc->elementLocalName, desc->elementNs )) != S_OK) return hr;
+
+    for (i = 0; i < count; i++)
+    {
+        if (params[i].inputMessageIndex == INVALID_PARAMETER_INDEX) continue;
+        if (params[i].parameterType == WS_PARAMETER_TYPE_MESSAGES)
+        {
+            FIXME( "messages type not supported\n" );
+            return E_NOTIMPL;
+        }
+        if ((hr = get_param_desc( desc_struct, params[i].inputMessageIndex, &desc_field )) != S_OK) return hr;
+        if (params[i].parameterType == WS_PARAMETER_TYPE_NORMAL)
+        {
+            if ((hr = write_param( writer, desc_field, args[i] )) != S_OK) return hr;
+        }
+        else if (params[i].parameterType == WS_PARAMETER_TYPE_ARRAY)
+        {
+            FIXME( "no support for writing array parameters\n" );
+        }
+    }
+
+    return write_endelement_node( writer );
+}
-- 
2.1.4




More information about the wine-patches mailing list