Commit d91f985e authored by Hans Leidekker's avatar Hans Leidekker Committed by Alexandre Julliard

webservices: Implement WsCall.

parent 5eb0971b
...@@ -64,24 +64,26 @@ struct header ...@@ -64,24 +64,26 @@ struct header
struct msg struct msg
{ {
WS_MESSAGE_INITIALIZATION init; WS_MESSAGE_INITIALIZATION init;
WS_MESSAGE_STATE state; WS_MESSAGE_STATE state;
GUID id; GUID id;
WS_ENVELOPE_VERSION version_env; WS_ENVELOPE_VERSION version_env;
WS_ADDRESSING_VERSION version_addr; WS_ADDRESSING_VERSION version_addr;
BOOL is_addressed; BOOL is_addressed;
WS_STRING addr; WS_STRING addr;
WS_STRING action; WS_STRING action;
WS_HEAP *heap; WS_HEAP *heap;
WS_XML_BUFFER *buf; WS_XML_BUFFER *buf;
WS_XML_WRITER *writer; WS_XML_WRITER *writer;
WS_XML_WRITER *writer_body; WS_XML_WRITER *writer_body;
WS_XML_READER *reader_body; WS_XML_READER *reader_body;
ULONG header_count; ULONG header_count;
ULONG header_size; ULONG header_size;
struct header **header; struct header **header;
ULONG prop_count; WS_PROXY_MESSAGE_CALLBACK_CONTEXT ctx_send;
struct prop prop[sizeof(msg_props)/sizeof(msg_props[0])]; 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 #define HEADER_ARRAY_SIZE 2
...@@ -953,7 +955,7 @@ static HRESULT build_mapped_header( const WS_XML_STRING *name, WS_TYPE type, WS_ ...@@ -953,7 +955,7 @@ static HRESULT build_mapped_header( const WS_XML_STRING *name, WS_TYPE type, WS_
* WsAddMappedHeader [webservices.@] * WsAddMappedHeader [webservices.@]
*/ */
HRESULT WINAPI WsAddMappedHeader( WS_MESSAGE *handle, const WS_XML_STRING *name, WS_TYPE type, 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 msg *msg = (struct msg *)handle;
struct header *header; struct header *header;
...@@ -1209,6 +1211,44 @@ HRESULT message_insert_http_headers( WS_MESSAGE *handle, HINTERNET req ) ...@@ -1209,6 +1211,44 @@ HRESULT message_insert_http_headers( WS_MESSAGE *handle, HINTERNET req )
return S_OK; 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 ) HRESULT message_set_action( WS_MESSAGE *handle, const WS_XML_STRING *action )
{ {
struct msg *msg = (struct msg *)handle; struct msg *msg = (struct msg *)handle;
......
...@@ -245,6 +245,127 @@ HRESULT WINAPI WsAbortServiceProxy( WS_SERVICE_PROXY *handle, WS_ERROR *error ) ...@@ -245,6 +245,127 @@ HRESULT WINAPI WsAbortServiceProxy( WS_SERVICE_PROXY *handle, WS_ERROR *error )
return E_NOTIMPL; 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.@] * WsCall [webservices.@]
*/ */
...@@ -252,6 +373,35 @@ HRESULT WINAPI WsCall( WS_SERVICE_PROXY *handle, const WS_OPERATION_DESCRIPTION ...@@ -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, WS_HEAP *heap, const WS_CALL_PROPERTY *properties, const ULONG count,
const WS_ASYNC_CONTEXT *ctx, WS_ERROR *error ) 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 ); struct proxy *proxy = (struct proxy *)handle;
return E_NOTIMPL; 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 ...@@ -4665,3 +4665,107 @@ HRESULT WINAPI WsReadCharsUtf8( WS_XML_READER *handle, BYTE *bytes, ULONG max_co
return S_OK; 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 ) ...@@ -249,6 +249,211 @@ static void test_WsReceiveMessage( int port )
WsFreeMessage( msg ); 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 static const struct
{ {
const char *req_action; const char *req_action;
...@@ -261,6 +466,7 @@ static const struct ...@@ -261,6 +466,7 @@ static const struct
tests[] = tests[] =
{ {
{ "req_test1", req_test1, sizeof(req_test1)-1, "resp_test1", resp_test1, sizeof(resp_test1)-1 }, { "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 ) 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 ) ...@@ -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 ); 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 ); send_response( c, tests[j].resp_action, tests[j].resp_data, tests[j].resp_len );
break;
} }
} }
...@@ -383,6 +590,7 @@ START_TEST(proxy) ...@@ -383,6 +590,7 @@ START_TEST(proxy)
test_WsSendMessage( info.port, &test1 ); test_WsSendMessage( info.port, &test1 );
test_WsReceiveMessage( info.port ); test_WsReceiveMessage( info.port );
test_WsCall( info.port );
test_WsSendMessage( info.port, &quit ); test_WsSendMessage( info.port, &quit );
WaitForSingleObject( thread, 3000 ); WaitForSingleObject( thread, 3000 );
......
...@@ -41,6 +41,13 @@ HRESULT set_output( WS_XML_WRITER * ) DECLSPEC_HIDDEN; ...@@ -41,6 +41,13 @@ HRESULT set_output( WS_XML_WRITER * ) DECLSPEC_HIDDEN;
HRESULT set_input( WS_XML_READER *, char *, ULONG ) DECLSPEC_HIDDEN; HRESULT set_input( WS_XML_READER *, char *, ULONG ) DECLSPEC_HIDDEN;
ULONG get_type_size( WS_TYPE, const WS_STRUCT_DESCRIPTION * ) 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 enum node_flag
{ {
NODE_FLAG_IGNORE_TRAILING_ELEMENT_CONTENT = 0x1, NODE_FLAG_IGNORE_TRAILING_ELEMENT_CONTENT = 0x1,
...@@ -100,6 +107,10 @@ HRESULT prop_set( const struct prop *, ULONG, ULONG, const void *, ULONG ) DECLS ...@@ -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 prop_get( const struct prop *, ULONG, ULONG, void *, ULONG ) DECLSPEC_HIDDEN;
HRESULT message_set_action( WS_MESSAGE *, const WS_XML_STRING * ) 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 message_insert_http_headers( WS_MESSAGE *, HINTERNET ) DECLSPEC_HIDDEN;
HRESULT channel_send_message( WS_CHANNEL *, WS_MESSAGE * ) 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 ...@@ -2107,7 +2107,7 @@ static HRESULT write_type_struct( struct writer *writer, WS_TYPE_MAPPING mapping
if (!desc) return E_INVALIDARG; if (!desc) return E_INVALIDARG;
if (desc->structOptions) FIXME( "struct options 0x%x not supported\n", desc->structOptions ); 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++) for (i = 0; i < desc->fieldCount; i++)
{ {
...@@ -2792,3 +2792,43 @@ HRESULT WINAPI WsCopyNode( WS_XML_WRITER *handle, WS_XML_READER *reader, WS_ERRO ...@@ -2792,3 +2792,43 @@ HRESULT WINAPI WsCopyNode( WS_XML_WRITER *handle, WS_XML_READER *reader, WS_ERRO
writer->current = current; writer->current = current;
return S_OK; 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 );
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment