diff --git a/dlls/webservices/msg.c b/dlls/webservices/msg.c
index 156060d50de..6d61aa066a8 100644
--- a/dlls/webservices/msg.c
+++ b/dlls/webservices/msg.c
@@ -1081,6 +1081,69 @@ done:
return hr;
}
+static HRESULT get_standard_header( struct msg *msg, WS_HEADER_TYPE type, WS_TYPE value_type,
+ WS_READ_OPTION option, WS_HEAP *heap, void *value, ULONG size )
+{
+ const WS_XML_STRING *localname = get_header_name( type );
+ const WS_XML_STRING *ns = get_addr_namespace( msg->version_addr );
+ const WS_XML_ELEMENT_NODE *elem;
+ const WS_XML_NODE *node;
+ HRESULT hr;
+
+ if (!heap) heap = msg->heap;
+ if (!msg->reader && (hr = WsCreateReader( NULL, 0, &msg->reader, NULL )) != S_OK) return hr;
+ if ((hr = WsSetInputToBuffer( msg->reader, msg->buf, NULL, 0, NULL )) != S_OK) return hr;
+
+ for (;;)
+ {
+ if ((hr = WsReadNode( msg->reader, NULL )) != S_OK) return hr;
+ if ((hr = WsGetReaderNode( msg->reader, &node, NULL )) != S_OK) return hr;
+ if (node->nodeType == WS_XML_NODE_TYPE_EOF) return WS_E_INVALID_FORMAT;
+ if (node->nodeType != WS_XML_NODE_TYPE_ELEMENT) continue;
+
+ elem = (const WS_XML_ELEMENT_NODE *)node;
+ if (WsXmlStringEquals( elem->localName, localname, NULL ) == S_OK &&
+ WsXmlStringEquals( elem->ns, ns, NULL ) == S_OK) break;
+ }
+
+ return read_header( msg->reader, localname, ns, value_type, NULL, option, heap, value, size );
+}
+
+/**************************************************************************
+ * WsGetHeader [webservices.@]
+ */
+HRESULT WINAPI WsGetHeader( WS_MESSAGE *handle, WS_HEADER_TYPE type, WS_TYPE value_type, WS_READ_OPTION option,
+ WS_HEAP *heap, void *value, ULONG size, WS_ERROR *error )
+{
+ struct msg *msg = (struct msg *)handle;
+ HRESULT hr;
+
+ TRACE( "%p %u %u %08x %p %p %u %p\n", handle, type, value_type, option, heap, value, size, error );
+ if (error) FIXME( "ignoring error parameter\n" );
+
+ if (!msg || type < WS_ACTION_HEADER || type > WS_FAULT_TO_HEADER || option < WS_READ_REQUIRED_VALUE ||
+ option > WS_READ_OPTIONAL_POINTER) return E_INVALIDARG;
+
+ EnterCriticalSection( &msg->cs );
+
+ if (msg->magic != MSG_MAGIC)
+ {
+ LeaveCriticalSection( &msg->cs );
+ return E_INVALIDARG;
+ }
+
+ if (msg->state < WS_MESSAGE_STATE_INITIALIZED)
+ {
+ LeaveCriticalSection( &msg->cs );
+ return WS_E_INVALID_OPERATION;
+ }
+
+ hr = get_standard_header( msg, type, value_type, option, heap, value, size );
+
+ LeaveCriticalSection( &msg->cs );
+ return hr;
+}
+
static void remove_header( struct msg *msg, ULONG i )
{
free_header( msg->header[i] );
diff --git a/dlls/webservices/reader.c b/dlls/webservices/reader.c
index d59de3bad0d..7c0a2eb3fa4 100644
--- a/dlls/webservices/reader.c
+++ b/dlls/webservices/reader.c
@@ -5242,6 +5242,28 @@ HRESULT WINAPI WsReadType( WS_XML_READER *handle, WS_TYPE_MAPPING mapping, WS_TY
return hr;
}
+HRESULT read_header( WS_XML_READER *handle, const WS_XML_STRING *localname, const WS_XML_STRING *ns,
+ WS_TYPE type, const void *desc, WS_READ_OPTION option, WS_HEAP *heap, void *value,
+ ULONG size )
+{
+ struct reader *reader = (struct reader *)handle;
+ HRESULT hr;
+
+ EnterCriticalSection( &reader->cs );
+
+ if (reader->magic != READER_MAGIC)
+ {
+ LeaveCriticalSection( &reader->cs );
+ return E_INVALIDARG;
+ }
+
+ hr = read_type( reader, WS_ELEMENT_CONTENT_TYPE_MAPPING, type, localname, ns, desc, option, heap,
+ value, size );
+
+ LeaveCriticalSection( &reader->cs );
+ return hr;
+}
+
/**************************************************************************
* WsReadElement [webservices.@]
*/
diff --git a/dlls/webservices/tests/msg.c b/dlls/webservices/tests/msg.c
index 4d252659300..4b33b55163e 100644
--- a/dlls/webservices/tests/msg.c
+++ b/dlls/webservices/tests/msg.c
@@ -1164,6 +1164,110 @@ static void test_WsResetMessage(void)
WsFreeMessage( msg );
}
+static void test_WsGetHeader(void)
+{
+ static char expected[] =
+ ""
+ "urn:uuid:00000000-0000-0000-0000-000000000000"
+ "action";
+ static char expected2[] =
+ "";
+ static char expected3[] =
+ ""
+ "action"
+ "";
+ static WCHAR action[] = {'a','c','t','i','o','n',0};
+ WS_MESSAGE *msg;
+ WCHAR *ptr;
+ HRESULT hr;
+
+ hr = WsGetHeader( NULL, 0, 0, 0, NULL, NULL, 0, NULL );
+ ok( hr == E_INVALIDARG, "got %08x\n", hr );
+
+ hr = WsCreateMessage( WS_ENVELOPE_VERSION_SOAP_1_2, WS_ADDRESSING_VERSION_1_0, NULL, 0, &msg, NULL );
+ ok( hr == S_OK, "got %08x\n", hr );
+
+ hr = WsGetHeader( msg, 0, 0, 0, NULL, NULL, 0, NULL );
+ ok( hr == E_INVALIDARG, "got %08x\n", hr );
+
+ hr = WsInitializeMessage( msg, WS_REQUEST_MESSAGE, NULL, NULL );
+ ok( hr == S_OK, "got %08x\n", hr );
+
+ hr = WsGetHeader( msg, 0, 0, 0, NULL, NULL, 0, NULL );
+ ok( hr == E_INVALIDARG, "got %08x\n", hr );
+
+ hr = WsGetHeader( msg, WS_ACTION_HEADER, 0, 0, NULL, NULL, 0, NULL );
+ ok( hr == E_INVALIDARG, "got %08x\n", hr );
+
+ hr = WsGetHeader( msg, WS_ACTION_HEADER, WS_WSZ_TYPE, 0, NULL, NULL, 0, NULL );
+ ok( hr == E_INVALIDARG, "got %08x\n", hr );
+
+ hr = WsGetHeader( msg, WS_ACTION_HEADER, WS_WSZ_TYPE, WS_READ_NILLABLE_POINTER, NULL, NULL, 0, NULL );
+ ok( hr == E_INVALIDARG, "got %08x\n", hr );
+
+ hr = WsGetHeader( msg, WS_ACTION_HEADER, WS_WSZ_TYPE, WS_READ_REQUIRED_POINTER, NULL, NULL, 0, NULL );
+ ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
+
+ ptr = action;
+ hr = WsSetHeader( msg, WS_ACTION_HEADER, WS_WSZ_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr, sizeof(ptr), NULL );
+ ok( hr == S_OK, "got %08x\n", hr );
+ check_output_header( msg, expected, -1, strstr(expected, "urn:uuid:") - expected, 46, __LINE__ );
+
+ hr = WsGetHeader( msg, WS_ACTION_HEADER, WS_WSZ_TYPE, WS_READ_REQUIRED_POINTER, NULL, NULL, 0, NULL );
+ ok( hr == E_INVALIDARG, "got %08x\n", hr );
+
+ ptr = NULL;
+ hr = WsGetHeader( msg, WS_ACTION_HEADER, WS_WSZ_TYPE, WS_READ_REQUIRED_POINTER, NULL, &ptr, 0, NULL );
+ ok( hr == E_INVALIDARG, "got %08x\n", hr );
+
+ ptr = NULL;
+ hr = WsGetHeader( msg, WS_ACTION_HEADER, WS_WSZ_TYPE, WS_READ_REQUIRED_POINTER, NULL, &ptr, sizeof(ptr), NULL );
+ ok( hr == S_OK, "got %08x\n", hr );
+ ok( ptr != NULL, "ptr not set\n" );
+ ok( !memcmp( ptr, action, sizeof(action) ), "wrong data\n" );
+ WsFreeMessage( msg );
+
+ hr = WsCreateMessage( WS_ENVELOPE_VERSION_NONE, WS_ADDRESSING_VERSION_TRANSPORT, NULL, 0, &msg, NULL );
+ ok( hr == S_OK, "got %08x\n", hr );
+
+ hr = WsInitializeMessage( msg, WS_REQUEST_MESSAGE, NULL, NULL );
+ ok( hr == S_OK, "got %08x\n", hr );
+
+ ptr = action;
+ hr = WsSetHeader( msg, WS_ACTION_HEADER, WS_WSZ_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr, sizeof(ptr), NULL );
+ ok( hr == S_OK, "got %08x\n", hr );
+ if (hr == S_OK) check_output_header( msg, expected2, -1, 0, 0, __LINE__ );
+
+ ptr = NULL;
+ hr = WsGetHeader( msg, WS_ACTION_HEADER, WS_WSZ_TYPE, WS_READ_REQUIRED_POINTER, NULL, &ptr, sizeof(ptr), NULL );
+ ok( hr == S_OK, "got %08x\n", hr );
+ ok( ptr != NULL, "ptr not set\n" );
+ ok( !memcmp( ptr, action, sizeof(action) ), "wrong data\n" );
+ WsFreeMessage( msg );
+
+ hr = WsCreateMessage( WS_ENVELOPE_VERSION_SOAP_1_2, WS_ADDRESSING_VERSION_TRANSPORT, NULL, 0, &msg, NULL );
+ ok( hr == S_OK, "got %08x\n", hr );
+
+ hr = WsInitializeMessage( msg, WS_REQUEST_MESSAGE, NULL, NULL );
+ ok( hr == S_OK, "got %08x\n", hr );
+
+ ptr = action;
+ hr = WsSetHeader( msg, WS_ACTION_HEADER, WS_WSZ_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr, sizeof(ptr), NULL );
+ ok( hr == S_OK, "got %08x\n", hr );
+ if (hr == S_OK) check_output_header( msg, expected3, -1, 0, 0, __LINE__ );
+
+ ptr = NULL;
+ hr = WsGetHeader( msg, WS_ACTION_HEADER, WS_WSZ_TYPE, WS_READ_REQUIRED_POINTER, NULL, &ptr, sizeof(ptr), NULL );
+ ok( hr == S_OK, "got %08x\n", hr );
+ ok( ptr != NULL, "ptr not set\n" );
+ ok( !memcmp( ptr, action, sizeof(action) ), "wrong data\n" );
+ WsFreeMessage( msg );
+}
+
START_TEST(msg)
{
test_WsCreateMessage();
@@ -1183,4 +1287,5 @@ START_TEST(msg)
test_WsReadEnvelopeEnd();
test_WsReadBody();
test_WsResetMessage();
+ test_WsGetHeader();
}
diff --git a/dlls/webservices/webservices.spec b/dlls/webservices/webservices.spec
index c88935aa75c..b6f246c417c 100644
--- a/dlls/webservices/webservices.spec
+++ b/dlls/webservices/webservices.spec
@@ -66,7 +66,7 @@
@ stdcall WsGetErrorString(ptr long ptr)
@ stub WsGetFaultErrorDetail
@ stub WsGetFaultErrorProperty
-@ stub WsGetHeader
+@ stdcall WsGetHeader(ptr long long long ptr ptr long ptr)
@ stub WsGetHeaderAttributes
@ stdcall WsGetHeapProperty(ptr long ptr long ptr)
@ stdcall WsGetListenerProperty(ptr long ptr long ptr)
diff --git a/dlls/webservices/webservices_private.h b/dlls/webservices/webservices_private.h
index db839b447a5..30bce24d6bb 100644
--- a/dlls/webservices/webservices_private.h
+++ b/dlls/webservices/webservices_private.h
@@ -45,6 +45,8 @@ BOOL set_fpword( unsigned short, unsigned short * ) DECLSPEC_HIDDEN;
void restore_fpword( unsigned short ) DECLSPEC_HIDDEN;
HRESULT set_output( WS_XML_WRITER * ) DECLSPEC_HIDDEN;
ULONG get_type_size( WS_TYPE, const WS_STRUCT_DESCRIPTION * ) DECLSPEC_HIDDEN;
+HRESULT read_header( WS_XML_READER *, const WS_XML_STRING *, const WS_XML_STRING *, WS_TYPE,
+ const void *, WS_READ_OPTION, WS_HEAP *, void *, ULONG ) DECLSPEC_HIDDEN;
#define INVALID_PARAMETER_INDEX 0xffff
HRESULT get_param_desc( const WS_STRUCT_DESCRIPTION *, USHORT, const WS_FIELD_DESCRIPTION ** ) DECLSPEC_HIDDEN;