webservices: Implement WsCall.
Signed-off-by: Hans Leidekker <hans@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
5eb0971be8
commit
d91f985e22
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue