[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