-- v3: webservices: Support faults in error. webservices: Implement error strings.
From: Shaun Ren sren@codeweavers.com
Signed-off-by: Shaun Ren sren@codeweavers.com --- dlls/webservices/error.c | 142 ++++++++++++++++++++++++++++-- dlls/webservices/tests/reader.c | 81 ++++++++++++++++- dlls/webservices/webservices.spec | 2 +- include/webservices.h | 1 + 4 files changed, 216 insertions(+), 10 deletions(-)
diff --git a/dlls/webservices/error.c b/dlls/webservices/error.c index d5364e42bff..d188b229ff4 100644 --- a/dlls/webservices/error.c +++ b/dlls/webservices/error.c @@ -41,8 +41,12 @@ struct error { ULONG magic; CRITICAL_SECTION cs; + WS_HEAP *heap; ULONG prop_count; struct prop prop[ARRAY_SIZE( error_props )]; + ULONG strs_count; + ULONG strs_size; /* Maximum length of the strs array */ + WS_STRING *strs; };
#define ERROR_MAGIC (('E' << 24) | ('R' << 16) | ('R' << 8) | 'O') @@ -54,6 +58,11 @@ static struct error *alloc_error(void) ULONG size = sizeof(*ret) + prop_size( error_props, count );
if (!(ret = calloc( 1, size ))) return NULL; + if (WsCreateHeap( 1 << 20, 0, NULL, 0, &ret->heap, NULL ) != S_OK) + { + free( ret ); + return NULL; + }
ret->magic = ERROR_MAGIC; InitializeCriticalSection( &ret->cs ); @@ -61,16 +70,51 @@ static struct error *alloc_error(void)
prop_init( error_props, count, ret->prop, &ret[1] ); ret->prop_count = count; + + ret->strs = NULL; + ret->strs_count = ret->strs_size = 0; + return ret; }
static void free_error( struct error *error ) { + WsFreeHeap( error->heap ); error->cs.DebugInfo->Spare[0] = 0; DeleteCriticalSection( &error->cs ); free( error ); }
+/* Grow the strs array to fit an extra element. */ +static HRESULT grow_strs_array( struct error *error ) +{ + WS_STRING *new_ptr; + ULONG new_size; + + if (error->strs_count < error->strs_size) + return S_OK; + + new_size = error->strs_size > 0 ? 2 * error->strs_size : 1; + if (error->strs_size > 0) + { + new_size = 2 * error->strs_size; + new_ptr = ws_realloc_zero( error->heap, error->strs, + error->strs_size * sizeof(WS_STRING), + new_size * sizeof(WS_STRING) ); + } + else + { + new_size = 1; + new_ptr = ws_alloc_zero( error->heap, sizeof(WS_STRING) ); + } + if (!new_ptr) + return E_OUTOFMEMORY; + + error->strs = new_ptr; + error->strs_size = new_size; + return S_OK; +} + /************************************************************************** * WsCreateError [webservices.@] */ @@ -111,8 +155,12 @@ HRESULT WINAPI WsCreateError( const WS_ERROR_PROPERTY *properties, ULONG count, static void reset_error( struct error *error ) { ULONG code = 0; - /* FIXME: release strings added with WsAddErrorString when it's implemented, reset string count */ + prop_set( error->prop, error->prop_count, WS_ERROR_PROPERTY_ORIGINAL_ERROR_CODE, &code, sizeof(code) ); + + error->strs = NULL; + error->strs_count = error->strs_size = 0; + WsResetHeap( error->heap, NULL ); }
/************************************************************************** @@ -175,22 +223,31 @@ HRESULT WINAPI WsGetErrorProperty( WS_ERROR *handle, WS_ERROR_PROPERTY_ID id, vo ULONG size ) { struct error *error = (struct error *)handle; - HRESULT hr; + HRESULT hr = S_OK;
TRACE( "%p %u %p %lu\n", handle, id, buf, size );
- if (!error) return E_INVALIDARG; + if (!error || !buf) return E_INVALIDARG;
EnterCriticalSection( &error->cs );
if (error->magic != ERROR_MAGIC) { - LeaveCriticalSection( &error->cs ); - return E_INVALIDARG; + hr = E_INVALIDARG; + goto done; }
- hr = prop_get( error->prop, error->prop_count, id, buf, size ); + if (id == WS_ERROR_PROPERTY_STRING_COUNT) + { + if (size == sizeof(ULONG)) + *(ULONG *)buf = error->strs_count; + else + hr = E_INVALIDARG; + } + else + hr = prop_get( error->prop, error->prop_count, id, buf, size );
+done: LeaveCriticalSection( &error->cs ); TRACE( "returning %#lx\n", hr ); return hr; @@ -201,8 +258,33 @@ HRESULT WINAPI WsGetErrorProperty( WS_ERROR *handle, WS_ERROR_PROPERTY_ID id, vo */ HRESULT WINAPI WsGetErrorString( WS_ERROR *handle, ULONG index, WS_STRING *str ) { - FIXME( "%p %lu %p: stub\n", handle, index, str ); - return E_NOTIMPL; + struct error *error = (struct error *)handle; + HRESULT hr = S_OK; + + TRACE( "%p %lu %p\n", handle, index, str ); + + if (!error || !str) return E_INVALIDARG; + + EnterCriticalSection( &error->cs ); + + if (error->magic != ERROR_MAGIC) + { + hr = E_INVALIDARG; + goto done; + } + if (index >= error->strs_count) + { + hr = E_INVALIDARG; + goto done; + } + + /* The strings are indexed from most recently added to least recently added. */ + memcpy( str, &error->strs[error->strs_count - 1 - index], sizeof(WS_STRING) ); + +done: + LeaveCriticalSection( &error->cs ); + TRACE( "returning %#lx\n", hr ); + return hr; }
/************************************************************************** @@ -233,3 +315,47 @@ HRESULT WINAPI WsSetErrorProperty( WS_ERROR *handle, WS_ERROR_PROPERTY_ID id, co TRACE( "returning %#lx\n", hr ); return hr; } + +/************************************************************************** + * WsAddErrorString [webservices.@] + */ +HRESULT WINAPI WsAddErrorString( WS_ERROR *handle, const WS_STRING *str ) +{ + struct error *error = (struct error *)handle; + WCHAR *chars; + HRESULT hr; + + TRACE( "%p %p\n", handle, str ); + + if (!error || !str) return E_INVALIDARG; + + EnterCriticalSection( &error->cs ); + + if (error->magic != ERROR_MAGIC) + { + hr = E_INVALIDARG; + goto done; + } + if (!(chars = ws_alloc( error->heap, str->length * sizeof(*chars) ))) + { + hr = E_OUTOFMEMORY; + goto done; + } + + if ( (hr = grow_strs_array( error )) != S_OK ) + { + ws_free( error->heap, chars, str->length * sizeof(*chars) ); + goto done; + } + + memcpy( chars, str->chars, str->length * sizeof(*chars) ); + + error->strs[error->strs_count].chars = chars; + error->strs[error->strs_count].length = str->length; + error->strs_count++; + +done: + LeaveCriticalSection( &error->cs ); + TRACE( "returning %#lx\n", hr ); + return hr; +} diff --git a/dlls/webservices/tests/reader.c b/dlls/webservices/tests/reader.c index f62697b9662..84a8660d6f1 100644 --- a/dlls/webservices/tests/reader.c +++ b/dlls/webservices/tests/reader.c @@ -3890,9 +3890,10 @@ static void test_WsReadValue(void) static void test_WsResetError(void) { WS_ERROR_PROPERTY prop; - ULONG size, code; + ULONG size, code, count; WS_ERROR *error; LANGID langid; + WS_STRING str; HRESULT hr;
hr = WsResetError( NULL ); @@ -3942,6 +3943,34 @@ static void test_WsResetError(void) ok( langid == MAKELANGID( LANG_DUTCH, SUBLANG_DEFAULT ), "got %u\n", langid );
WsFreeError( error ); + + str.chars = (WCHAR *) L"str"; + str.length = 3; + + hr = WsCreateError( NULL, 0, &error ); + ok( hr == S_OK, "got %#lx\n", hr ); + + hr = WsAddErrorString(error, &str ); + ok( hr == S_OK, "got %#lx\n", hr ); + hr = WsAddErrorString(error, &str ); + ok( hr == S_OK, "got %#lx\n", hr ); + + count = 0xdeadbeef; + size = sizeof(count); + hr = WsGetErrorProperty( error, WS_ERROR_PROPERTY_STRING_COUNT, &count, size ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( count == 2, "got %lu\n", count ); + + hr = WsResetError( error ); + ok( hr == S_OK, "got %#lx\n", hr ); + + count = 0xdeadbeef; + size = sizeof(count); + hr = WsGetErrorProperty( error, WS_ERROR_PROPERTY_STRING_COUNT, &count, size ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( count == 0, "got %lu\n", count ); + + WsFreeError( error ); }
static void test_WsGetReaderPosition(void) @@ -7044,6 +7073,55 @@ static void test_description_type(void) WsFreeHeap( heap ); }
+static void test_WsAddErrorString(void) +{ + ULONG count; + WS_ERROR *error; + WS_STRING emptystr = { 0 }; + WS_STRING str1 = { 4, (WCHAR *) L"str1" }; + WS_STRING str2 = { 4, (WCHAR *) L"str2" }; + WS_STRING out; + HRESULT hr; + + hr = WsCreateError( NULL, 0, &error ); + ok( hr == S_OK, "got %#lx\n", hr ); + + hr = WsAddErrorString( NULL, NULL ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); + hr = WsAddErrorString( NULL, &str1 ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); + hr = WsAddErrorString( error, NULL ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); + + hr = WsAddErrorString( error, &emptystr ); + ok( hr == S_OK, "got %#lx\n", hr ); + hr = WsAddErrorString(error, &str2 ); + ok( hr == S_OK, "got %#lx\n", hr ); + hr = WsAddErrorString(error, &str1 ); + ok( hr == S_OK, "got %#lx\n", hr ); + + count = 0xdeadbeef; + hr = WsGetErrorProperty( error, WS_ERROR_PROPERTY_STRING_COUNT, &count, sizeof(count) ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( count == 3, "got %lu\n", count ); + + hr = WsGetErrorString( error, 0, &out ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( out.length == str1.length, "got %lu\n", out.length ); + ok( !memcmp( out.chars, str1.chars, str1.length ), "wrong error string\n" ); + + hr = WsGetErrorString( error, 1, &out ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( out.length == str2.length, "got %lu\n", out.length ); + ok( !memcmp( out.chars, str2.chars, str2.length ), "wrong error string\n" ); + + hr = WsGetErrorString( error, 2, &out ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( out.length == 0, "got %lu\n", out.length ); + ok( out.chars != NULL, "out.chars == NULL\n" ); + + WsFreeError( error ); +} START_TEST(reader) { test_WsCreateError(); @@ -7095,4 +7173,5 @@ START_TEST(reader) test_empty_text_field(); test_stream_input(); test_description_type(); + test_WsAddErrorString(); } diff --git a/dlls/webservices/webservices.spec b/dlls/webservices/webservices.spec index 3fe1f4d4275..679d294ec1c 100644 --- a/dlls/webservices/webservices.spec +++ b/dlls/webservices/webservices.spec @@ -6,7 +6,7 @@ @ stdcall WsAbortServiceProxy(ptr ptr) @ stdcall WsAcceptChannel(ptr ptr ptr ptr) @ stdcall WsAddCustomHeader(ptr ptr long ptr long long ptr) -@ stub WsAddErrorString +@ stdcall WsAddErrorString(ptr ptr) @ stdcall WsAddMappedHeader(ptr ptr long long ptr long ptr) @ stdcall WsAddressMessage(ptr ptr ptr) @ stdcall WsAlloc(ptr long ptr ptr) diff --git a/include/webservices.h b/include/webservices.h index a6018d5d258..9395ad6f0e3 100644 --- a/include/webservices.h +++ b/include/webservices.h @@ -1588,6 +1588,7 @@ HRESULT WINAPI WsAbortServiceProxy(WS_SERVICE_PROXY*, WS_ERROR*); HRESULT WINAPI WsAcceptChannel(WS_LISTENER*, WS_CHANNEL*, const WS_ASYNC_CONTEXT*, WS_ERROR*); HRESULT WINAPI WsAddCustomHeader(WS_MESSAGE*, const WS_ELEMENT_DESCRIPTION*, WS_WRITE_OPTION, const void*, ULONG, ULONG, WS_ERROR*); +HRESULT WINAPI WsAddErrorString(WS_ERROR*, const WS_STRING*); HRESULT WINAPI WsAddMappedHeader(WS_MESSAGE*, const WS_XML_STRING*, WS_TYPE, WS_WRITE_OPTION, const void*, ULONG, WS_ERROR*); HRESULT WINAPI WsAddressMessage(WS_MESSAGE*, const WS_ENDPOINT_ADDRESS*, WS_ERROR*);
From: Shaun Ren sren@codeweavers.com
Signed-off-by: Shaun Ren sren@codeweavers.com --- dlls/webservices/error.c | 348 +++++++++++++++++++++++++ dlls/webservices/tests/reader.c | 310 ++++++++++++++++++++++ dlls/webservices/webservices.spec | 6 +- dlls/webservices/webservices_private.h | 2 + include/webservices.h | 39 +++ 5 files changed, 702 insertions(+), 3 deletions(-)
diff --git a/dlls/webservices/error.c b/dlls/webservices/error.c index d188b229ff4..aa1a9744f34 100644 --- a/dlls/webservices/error.c +++ b/dlls/webservices/error.c @@ -47,6 +47,8 @@ struct error ULONG strs_count; ULONG strs_size; /* Maximum length of the strs array */ WS_STRING *strs; + WS_FAULT *fault; + WS_XML_STRING fault_action; };
#define ERROR_MAGIC (('E' << 24) | ('R' << 16) | ('R' << 8) | 'O') @@ -85,6 +87,60 @@ static void free_error( struct error *error ) free( error ); }
+void free_fault_fields( WS_HEAP *heap, WS_FAULT *fault ) +{ + WS_FAULT_CODE *code, *prev_code; + ULONG i; + + code = fault->code; + while ( code ) + { + ws_free( heap, code->value.localName.bytes, code->value.localName.length ); + ws_free( heap, code->value.ns.bytes, code->value.ns.length ); + prev_code = code; + code = code->subCode; + ws_free( heap, prev_code, sizeof(*prev_code) ); + } + + for (i = 0; i < fault->reasonCount; i++) + { + ws_free( heap, fault->reasons[i].text.chars, fault->reasons[i].text.length * sizeof(WCHAR) ); + ws_free( heap, fault->reasons[i].lang.chars, fault->reasons[i].lang.length * sizeof(WCHAR) ); + } + ws_free( heap, fault->reasons, fault->reasonCount * sizeof(*fault->reasons) ); + + ws_free( heap, fault->actor.chars, fault->actor.length * sizeof(WCHAR) ); + ws_free( heap, fault->node.chars, fault->node.length * sizeof(WCHAR) ); + free_xmlbuf((struct xmlbuf *)fault->detail); +} + +static void free_fault( WS_HEAP *heap, WS_FAULT *fault ) +{ + if (!fault) return; + free_fault_fields( heap, fault ); + ws_free( heap, fault, sizeof(*fault) ); +} + +static BOOL copy_xml_string( WS_HEAP *heap, const WS_XML_STRING *src, WS_XML_STRING *dst ) +{ + if (!src->length) return TRUE; + if (!(dst->bytes = ws_alloc( heap, src->length ))) return FALSE; + memcpy( dst->bytes, src->bytes, src->length ); + dst->length = src->length; + return TRUE; +} + +static BOOL copy_string( WS_HEAP *heap, const WS_STRING *src, WS_STRING *dst ) +{ + ULONG size; + if (!src->length) return TRUE; + size = src->length * sizeof(WCHAR); + if (!(dst->chars = ws_alloc( heap, size ))) return FALSE; + memcpy( dst->chars, src->chars, size ); + dst->length = src->length; + return TRUE; +} + /* Grow the strs array to fit an extra element. */ static HRESULT grow_strs_array( struct error *error ) { @@ -115,6 +171,142 @@ static HRESULT grow_strs_array( struct error *error ) return S_OK; }
+static WS_FAULT *dup_fault( WS_HEAP *heap, const WS_FAULT *src ) +{ + WS_FAULT *new_fault; + WS_FAULT_CODE *code, *prev_code, *new_code; + struct xmlbuf *buf, *new_buf; + ULONG i; + BOOL success = FALSE; + + if (!(new_fault = ws_alloc_zero( heap, sizeof(*new_fault) ))) + return NULL; + + prev_code = NULL; + code = src->code; + while ( code ) + { + if (!(new_code = ws_alloc_zero( heap, sizeof(*new_code) )) || + !copy_xml_string( heap, &code->value.localName, &new_code->value.localName ) || + !copy_xml_string( heap, &code->value.ns, &new_code->value.ns )) + goto done; + + if (prev_code) + prev_code->subCode = new_code; + else + new_fault->code = new_code; + prev_code = new_code; + code = code->subCode; + } + + if (src->reasonCount > 0) + { + if (!(new_fault->reasons = ws_alloc_zero( heap, sizeof(*new_fault->reasons) * src->reasonCount ))) + goto done; + new_fault->reasonCount = src->reasonCount; + for (i = 0; i < src->reasonCount; i++) + { + if (!copy_string( heap, &src->reasons[i].text, &new_fault->reasons[i].text ) || + !copy_string( heap, &src->reasons[i].lang, &new_fault->reasons[i].lang )) + goto done; + } + } + + if (!copy_string( heap, &src->actor, &new_fault->actor ) || + !copy_string( heap, &src->node, &new_fault->node )) + goto done; + + buf = (struct xmlbuf *)src->detail; + new_buf = NULL; + if (buf) + { + if (!(new_buf = alloc_xmlbuf( heap, buf->bytes.length, buf->encoding, + buf->charset, buf->dict_static, buf->dict ))) + goto done; + memcpy( new_buf->bytes.bytes, buf->bytes.bytes, buf->bytes.length ); + new_buf->bytes.length = buf->bytes.length; + } + new_fault->detail = (WS_XML_BUFFER *)new_buf; + + success = TRUE; +done: + if (!success) + { + free_fault( heap, new_fault ); + return NULL; + } + return new_fault; +} + +static HRESULT set_fault( struct error *error, const WS_FAULT *value ) +{ + static const WCHAR prefix[] = L"The fault reason was: '"; + static const WCHAR postfix[] = L"'."; + static const ULONG prefix_len = ARRAY_SIZE(prefix) - 1, postfix_len = ARRAY_SIZE(postfix) - 1; + WS_FAULT *fault; + WS_STRING *str; + WCHAR *dst; + ULONG len; + HRESULT hr = S_OK; + + if (!(fault = dup_fault( error->heap, value ))) + return E_OUTOFMEMORY; + + /* FIXME: check if reason lang matches error property langid */ + if (fault->reasonCount > 0) + { + if ((hr = grow_strs_array( error )) != S_OK) goto done; + + str = &error->strs[error->strs_count]; + len = prefix_len + fault->reasons[0].text.length + postfix_len; + if (!(str->chars = ws_alloc( error->heap, len * sizeof(WCHAR) ))) + { + hr = E_OUTOFMEMORY; + goto done; + } + + dst = str->chars; + memcpy( dst, prefix, prefix_len * sizeof(WCHAR) ); + dst += prefix_len; + memcpy( dst, fault->reasons[0].text.chars, fault->reasons[0].text.length * sizeof(WCHAR) ); + dst += fault->reasons[0].text.length; + memcpy( dst, postfix, postfix_len * sizeof(WCHAR) ); + + str->length = len; + error->strs_count++; + } + + free_fault( error->heap, error->fault ); + error->fault = fault; + +done: + if (hr != S_OK) + free_fault( error->heap, fault ); + return hr; +} + +static HRESULT set_action( struct error *error, const WS_XML_STRING *value ) +{ + BYTE *buf; + + if (value->length == 0) + { + ws_free( error->heap, error->fault_action.bytes, error->fault_action.length ); + memset( &error->fault_action, 0, sizeof(error->fault_action) ); + return S_OK; + } + + if (!(buf = ws_alloc( error->heap, value->length ))) + return E_OUTOFMEMORY; + + memcpy( buf, value->bytes, value->length ); + ws_free( error->heap, error->fault_action.bytes, error->fault_action.length ); + error->fault_action.bytes = buf; + error->fault_action.length = value->length; + + return S_OK; +} + /************************************************************************** * WsCreateError [webservices.@] */ @@ -160,6 +352,9 @@ static void reset_error( struct error *error )
error->strs = NULL; error->strs_count = error->strs_size = 0; + error->fault = NULL; + memset( &error->fault_action, 0, sizeof(error->fault_action) ); + WsResetHeap( error->heap, NULL ); }
@@ -359,3 +554,156 @@ done: TRACE( "returning %#lx\n", hr ); return hr; } + +/************************************************************************** + * WsGetFaultErrorDetail [webservices.@] + */ +HRESULT WINAPI WsGetFaultErrorDetail( WS_ERROR *handle, const WS_FAULT_DETAIL_DESCRIPTION *desc, + WS_READ_OPTION option, WS_HEAP *heap, void *value, ULONG size ) +{ + static const WS_XML_STRING detail = {6, (BYTE *)"detail"}; + struct error *error = (struct error *)handle; + WS_XML_READER *reader = NULL; + const WS_XML_NODE *node; + const WS_XML_ELEMENT_NODE *elem; + BOOL nil = FALSE; + HRESULT hr = S_OK; + + TRACE( "%p %p %u %p %p %lu\n", handle, desc, option, heap, value, size ); + + if (!error || !desc || !value) return E_INVALIDARG; + if ((option == WS_READ_REQUIRED_POINTER || + option == WS_READ_OPTIONAL_POINTER || + option == WS_READ_NILLABLE_POINTER) && size != sizeof(void *)) + return E_INVALIDARG; + + EnterCriticalSection( &error->cs ); + + if (error->magic != ERROR_MAGIC) + { + hr = E_INVALIDARG; + goto done; + } + + if (!error->fault || !error->fault->detail) + { + nil = TRUE; + goto done; + } + if ((hr = WsCreateReader( NULL, 0, &reader, NULL )) != S_OK) goto done; + if ((hr = WsSetInputToBuffer( reader, error->fault->detail, NULL, 0, NULL )) != S_OK) goto done; + + if ((hr = WsReadNode( reader, NULL )) != S_OK) goto done; + if ((hr = WsGetReaderNode( reader, &node, NULL )) != S_OK) goto done; + elem = (const WS_XML_ELEMENT_NODE *)node; + if (!(node->nodeType == WS_XML_NODE_TYPE_ELEMENT && + WsXmlStringEquals( elem->localName, &detail, NULL ) == S_OK)) + { + hr = WS_E_INVALID_FORMAT; + goto done; + } + + if (desc->action && error->fault_action.length && + WsXmlStringEquals( desc->action, &error->fault_action, NULL ) != S_OK) + { + nil = TRUE; + goto done; + } + + if ((hr = WsReadNode( reader, NULL )) != S_OK) goto done; + if ((hr = WsReadElement( reader, desc->detailElementDescription, + option, heap, value, size, handle )) != S_OK) + goto done; + +done: + LeaveCriticalSection( &error->cs ); + WsFreeReader( reader ); + + if ((hr != S_OK || nil) && (option == WS_READ_OPTIONAL_POINTER || option == WS_READ_NILLABLE_POINTER)) + *(void **)value = NULL; + if (nil && !(option == WS_READ_OPTIONAL_POINTER || option == WS_READ_NILLABLE_POINTER)) + hr = WS_E_INVALID_FORMAT; + + TRACE( "returning %#lx\n", hr ); + return hr; +} + +/************************************************************************** + * WsGetFaultErrorProperty [webservices.@] + */ +HRESULT WINAPI WsGetFaultErrorProperty( WS_ERROR *handle, WS_FAULT_ERROR_PROPERTY_ID id, + void *buf, ULONG size ) +{ + struct error *error = (struct error *)handle; + HRESULT hr = S_OK; + + TRACE( "%p %u %p %lu\n", handle, id, buf, size ); + + if (!error || !buf) return E_INVALIDARG; + if (id > WS_FAULT_ERROR_PROPERTY_HEADER) return E_INVALIDARG; + else if (id == WS_FAULT_ERROR_PROPERTY_HEADER) + { + FIXME( "WS_FAULT_ERROR_PROPERTY_HEADER not supported\n" ); + return E_NOTIMPL; + } + + EnterCriticalSection( &error->cs ); + + if (error->magic != ERROR_MAGIC) + { + hr = E_INVALIDARG; + goto done; + } + + if (id == WS_FAULT_ERROR_PROPERTY_FAULT && size == sizeof(WS_FAULT *)) + *(WS_FAULT **)buf = error->fault; + else if (id == WS_FAULT_ERROR_PROPERTY_ACTION && size == sizeof(WS_XML_STRING)) + memcpy( buf, &error->fault_action, sizeof(WS_XML_STRING) ); + else + hr = E_INVALIDARG; + +done: + LeaveCriticalSection( &error->cs ); + TRACE( "returning %#lx\n", hr ); + return hr; +} + +/************************************************************************** + * WsSetFaultErrorProperty [webservices.@] + */ +HRESULT WINAPI WsSetFaultErrorProperty( WS_ERROR *handle, WS_FAULT_ERROR_PROPERTY_ID id, + const void *value, ULONG size ) +{ + struct error *error = (struct error *)handle; + HRESULT hr = S_OK; + + TRACE( "%p %u %p %lu\n", handle, id, value, size ); + + if (!error || !value) return E_INVALIDARG; + if (id > WS_FAULT_ERROR_PROPERTY_HEADER) return E_INVALIDARG; + else if (id == WS_FAULT_ERROR_PROPERTY_HEADER) + { + FIXME( "WS_FAULT_ERROR_PROPERTY_HEADER not supported\n" ); + return E_NOTIMPL; + } + + EnterCriticalSection( &error->cs ); + + if (error->magic != ERROR_MAGIC) + { + hr = E_INVALIDARG; + goto done; + } + + if (id == WS_FAULT_ERROR_PROPERTY_FAULT && size == sizeof(WS_FAULT)) + hr = set_fault( error, value ); + else if (id == WS_FAULT_ERROR_PROPERTY_ACTION && size == sizeof(WS_XML_STRING)) + hr = set_action( error, value ); + else + hr = E_INVALIDARG; + +done: + LeaveCriticalSection( &error->cs ); + TRACE( "returning %#lx\n", hr ); + return hr; +} diff --git a/dlls/webservices/tests/reader.c b/dlls/webservices/tests/reader.c index 84a8660d6f1..2ade3c3d4b1 100644 --- a/dlls/webservices/tests/reader.c +++ b/dlls/webservices/tests/reader.c @@ -3894,6 +3894,9 @@ static void test_WsResetError(void) WS_ERROR *error; LANGID langid; WS_STRING str; + WS_FAULT fault; + WS_XML_STRING xmlstr; + WS_FAULT *faultp; HRESULT hr;
hr = WsResetError( NULL ); @@ -3971,6 +3974,34 @@ static void test_WsResetError(void) ok( count == 0, "got %lu\n", count );
WsFreeError( error ); + + memset( &fault, 0, sizeof(fault) ); + xmlstr.bytes = (BYTE *)"str"; + xmlstr.length = 3; + + hr = WsCreateError( NULL, 0, &error ); + ok( hr == S_OK, "got %#lx\n", hr ); + + hr = WsSetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_FAULT, &fault, sizeof(fault) ); + ok( hr == S_OK, "got %#lx\n", hr ); + hr = WsSetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_ACTION, &xmlstr, sizeof(WS_XML_STRING) ); + ok( hr == S_OK, "got %#lx\n", hr ); + + hr = WsResetError( error ); + ok( hr == S_OK, "got %#lx\n", hr ); + + faultp = (WS_FAULT *)0xdeadbeef; + hr = WsGetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_FAULT, &faultp, sizeof(faultp) ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( faultp == NULL, "faultp != NULL\n" ); + + xmlstr.length = 0xdeadbeef; + xmlstr.bytes = (BYTE *)0xdeadbeef; + hr = WsGetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_ACTION, &xmlstr, sizeof(xmlstr) ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( xmlstr.length == 0, "got %lu\n", xmlstr.length ); + + WsFreeError( error ); }
static void test_WsGetReaderPosition(void) @@ -7122,6 +7153,283 @@ static void test_WsAddErrorString(void)
WsFreeError( error ); } + +static void test_WsSetFaultErrorProperty(void) +{ + static const WCHAR expected_errorstr[] = L"The fault reason was: 'Some reason'."; + static const char detailxml[] = "<detail><ErrorCode>1030</ErrorCode></detail>"; + static const LANGID langid = MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ); + static const WS_XML_STRING action = { 24, (BYTE *)"http://example.com/fault" }; + WS_ERROR_PROPERTY prop; + WS_ERROR *error; + WS_FAULT fault; + WS_FAULT *faultp; + WS_XML_STRING outxmlstr; + WS_STRING outstr; + ULONG count; + WS_HEAP *heap; + WS_XML_READER *reader; + HRESULT hr; + + prop.id = WS_ERROR_PROPERTY_LANGID; + prop.value = (void *)&langid; + prop.valueSize = sizeof(langid); + + hr = WsCreateError( &prop, 1, &error ); + ok( hr == S_OK, "got %#lx\n", hr ); + + hr = WsSetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_FAULT, NULL, sizeof(WS_FAULT) ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); + + hr = WsSetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_ACTION, NULL, sizeof(WS_XML_STRING) ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); + + memset( &fault, 0, sizeof(fault) ); + + fault.code = calloc( 1, sizeof(WS_FAULT_CODE) ); + fault.code->value.localName.bytes = (BYTE *)"Server"; + fault.code->value.localName.length = 6; + fault.code->subCode = calloc( 1, sizeof(WS_FAULT_CODE) ); + fault.code->subCode->value.localName.bytes = (BYTE *)"SubCode"; + fault.code->subCode->value.localName.length = 7; + + fault.reasons = calloc( 1, sizeof(*fault.reasons) ); + fault.reasonCount = 1; + fault.reasons[0].lang.chars = (WCHAR *) L"en-US"; + fault.reasons[0].lang.length = 5; + fault.reasons[0].text.chars = (WCHAR *) L"Some reason"; + fault.reasons[0].text.length = 11; + + hr = WsSetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_FAULT, &fault, sizeof(WS_FAULT) ); + ok( hr == S_OK, "got %#lx\n", hr ); + + faultp = NULL; + hr = WsGetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_FAULT, &faultp, sizeof(faultp) ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( faultp != NULL, "faultp not set\n" ); + ok( faultp != &fault, "fault not copied\n" ); + + ok( faultp->code && faultp->code != fault.code, "fault code not copied\n" ); + ok( faultp->code->value.localName.length == 6, "got %lu\n", faultp->code->value.localName.length ); + ok( !memcmp( faultp->code->value.localName.bytes, fault.code->value.localName.bytes, 6 ), + "wrong code localName\n" ); + ok( faultp->code->value.localName.bytes != fault.code->value.localName.bytes, + "fault code localName not copied\n" ); + ok( faultp->code->value.ns.length == 0, "got %lu\n", faultp->code->value.ns.length ); + ok( faultp->code->subCode && faultp->code->subCode != fault.code->subCode, + "fault code subCode not copied\n" ); + ok( faultp->code->subCode->value.localName.length == 7,"got %lu\n", faultp->code->subCode->value.localName.length ); + ok( !memcmp( faultp->code->subCode->value.localName.bytes, fault.code->subCode->value.localName.bytes, 7 ), + "wrong subCode localName\n" ); + ok( faultp->code->subCode->value.localName.bytes != fault.code->subCode->value.localName.bytes, + "fault code subCode localName not copied\n" ); + ok( faultp->code->subCode->value.ns.length == 0, "got %lu\n", faultp->code->subCode->value.ns.length ); + ok( faultp->code->subCode->subCode == NULL, "fault->code->subCode->subCode != NULL\n"); + + ok( faultp->reasons != fault.reasons, "fault reasons not copied\n" ); + ok( faultp->reasonCount == 1, "got %lu\n", faultp->reasonCount ); + ok( faultp->reasons[0].lang.length == 5, "got %lu\n", faultp->reasons[0].text.length ); + ok( !memcmp( faultp->reasons[0].lang.chars, fault.reasons[0].lang.chars, 5 * sizeof(WCHAR) ), + "wrong fault reason lang\n" ); + ok( faultp->reasons[0].lang.chars != fault.reasons[0].lang.chars, + "fault reason lang not copied\n" ); + ok( faultp->reasons[0].text.length == 11, "got %lu\n", faultp->reasons[0].text.length ); + ok( !memcmp( faultp->reasons[0].text.chars, fault.reasons[0].text.chars, 11 * sizeof(WCHAR) ), + "wrong fault reason text\n" ); + ok( faultp->reasons[0].text.chars != fault.reasons[0].text.chars, + "fault reason text not copied\n" ); + + ok( faultp->actor.length == 0, "got %lu\n", faultp->actor.length ); + ok( faultp->node.length == 0, "got %lu\n", faultp->node.length ); + ok( faultp->detail == NULL, "faultp->detail != NULL\n" ); + + count = 0xdeadbeef; + hr = WsGetErrorProperty( error, WS_ERROR_PROPERTY_STRING_COUNT, &count, sizeof(count) ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( count == 1, "got %lu\n", count ); + + hr = WsGetErrorString( error, 0, &outstr ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( outstr.length == ARRAY_SIZE(expected_errorstr) - 1, "got %lu\n", outstr.length ); + ok( !memcmp( outstr.chars, expected_errorstr, (ARRAY_SIZE(expected_errorstr) - 1) * sizeof(WCHAR) ), + "wrong error string\n" ); + + outxmlstr.bytes = (BYTE *)0xdeadbeef; + outxmlstr.length = 0xdeadbeef; + hr = WsGetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_ACTION, &outxmlstr, sizeof(outxmlstr) ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( outxmlstr.length == 0, "got %lu\n", outxmlstr.length ); + + hr = WsSetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_ACTION, &action, sizeof(action) ); + ok( hr == S_OK, "got %#lx\n", hr ); + + outxmlstr.bytes = (BYTE *)0xdeadbeef; + outxmlstr.length = 0xdeadbeef; + hr = WsGetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_ACTION, &outxmlstr, sizeof(outxmlstr) ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( outxmlstr.length == 24, "got %lu\n", outxmlstr.length ); + ok( !memcmp( outxmlstr.bytes, action.bytes, 24 ), "wrong fault action\n" ); + + hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL ); + ok( hr == S_OK, "got %#lx\n", hr ); + hr = WsCreateReader( NULL, 0, &reader, NULL ); + ok( hr == S_OK, "got %#lx\n", hr ); + hr = set_input( reader, detailxml, strlen(detailxml) ); + ok( hr == S_OK, "got %#lx\n", hr ); + hr = WsReadXmlBuffer( reader, heap, &fault.detail, NULL ); + ok( hr == S_OK, "got %#lx\n", hr ); + + hr = WsSetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_FAULT, &fault, sizeof(WS_FAULT) ); + ok( hr == S_OK, "got %#lx\n", hr ); + + hr = WsGetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_FAULT, &faultp, sizeof(faultp) ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( faultp != NULL, "faultp not set\n" ); + ok( faultp->detail != NULL, "fault detail not set\n" ); + ok( faultp->detail != fault.detail, "fault detail not copied\n" ); + check_output_buffer( faultp->detail, detailxml, __LINE__ ); + + free( fault.code->subCode ); + free( fault.code ); + free( fault.reasons ); + WsFreeReader( reader ); + WsFreeHeap( heap ); + WsFreeError( error ); +} + +static void test_WsGetFaultErrorDetail(void) +{ + static const char detailxml[] = "<detail><ErrorCode>1030</ErrorCode></detail>"; + static const char badxml[] = "<bad><ErrorCode>1030</ErrorCode></bad>"; + + WS_ERROR *error; + WS_HEAP *heap; + WS_XML_READER *reader; + WS_FAULT fault; + WS_XML_STRING action = { 24, (BYTE *)"http://example.com/fault" }; + WS_XML_STRING action2 = { 25, (BYTE *)"http://example.com/fault2" }; + WS_XML_STRING localname = { 9, (BYTE *)"ErrorCode" }, localname2 = { 9, (BYTE *)"OtherCode" }; + WS_XML_STRING ns = { 0 }; + WS_ELEMENT_DESCRIPTION desc = { &localname, &ns, WS_UINT32_TYPE, NULL }; + WS_ELEMENT_DESCRIPTION desc2 = { &localname2, &ns, WS_UINT32_TYPE, NULL }; + WS_FAULT_DETAIL_DESCRIPTION fault_desc; + UINT32 code; + UINT32 *codep; + HRESULT hr; + + hr = WsCreateError( NULL, 0, &error ); + ok( hr == S_OK, "got %#lx\n", hr ); + + memset( &fault, 0, sizeof(fault) ); + + hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL ); + ok( hr == S_OK, "got %#lx\n", hr ); + hr = WsCreateReader( NULL, 0, &reader, NULL ); + ok( hr == S_OK, "got %#lx\n", hr ); + + hr = set_input( reader, detailxml, strlen(detailxml) ); + ok( hr == S_OK, "got %#lx\n", hr ); + hr = WsReadXmlBuffer( reader, heap, &fault.detail, NULL ); + ok( hr == S_OK, "got %#lx\n", hr ); + hr = WsSetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_FAULT, &fault, sizeof(fault) ); + ok( hr == S_OK, "got %#lx\n", hr ); + + fault_desc.action = NULL; + fault_desc.detailElementDescription = &desc; + + code = 0xdeadbeef; + hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_REQUIRED_VALUE, heap, &code, sizeof(code) ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( code == 1030, "got %u\n", code ); + + codep = (UINT32 *)0xdeadbeef; + hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_OPTIONAL_POINTER, heap, &codep, sizeof(codep) ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( codep != NULL, "codep == NULL\n" ); + ok( *codep == 1030, "got %u\n", *codep ); + + fault_desc.action = &action; + + code = 0xdeadbeef; + hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_REQUIRED_VALUE, heap, &code, sizeof(code) ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( code == 1030, "got %u\n", code ); + + hr = WsSetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_ACTION, &action, sizeof(action) ); + ok( hr == S_OK, "got %#lx\n", hr ); + + fault_desc.action = NULL; + + code = 0xdeadbeef; + hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_REQUIRED_VALUE, heap, &code, sizeof(code) ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( code == 1030, "got %u\n", code ); + + fault_desc.action = &action2; + + hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_REQUIRED_VALUE, heap, &code, sizeof(code) ); + ok( hr == WS_E_INVALID_FORMAT, "got %#lx\n", hr ); + + hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_REQUIRED_POINTER, heap, &codep, sizeof(codep) ); + ok( hr == WS_E_INVALID_FORMAT, "got %#lx\n", hr ); + + codep = (UINT32 *)0xdeadbeef; + hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_OPTIONAL_POINTER, heap, &codep, sizeof(codep) ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( codep == NULL, "codep != NULL\n" ); + + codep = (UINT32 *)0xdeadbeef; + hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_NILLABLE_POINTER, heap, &codep, sizeof(codep) ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( codep == NULL, "codep != NULL\n" ); + + fault_desc.action = NULL; + fault_desc.detailElementDescription = &desc2; + + hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_REQUIRED_VALUE, heap, &code, sizeof(code) ); + ok( hr == WS_E_INVALID_FORMAT, "got %#lx\n", hr ); + + hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_REQUIRED_POINTER, heap, &codep, sizeof(codep) ); + ok( hr == WS_E_INVALID_FORMAT, "got %#lx\n", hr ); + + codep = (UINT32 *)0xdeadbeef; + hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_OPTIONAL_POINTER, heap, &codep, sizeof(codep) ); + ok( hr == WS_E_INVALID_FORMAT, "got %#lx\n", hr ); + ok( codep == NULL, "codep != NULL\n" ); + + codep = (UINT32 *)0xdeadbeef; + hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_NILLABLE_POINTER, heap, &codep, sizeof(codep) ); + ok( hr == WS_E_INVALID_FORMAT, "got %#lx\n", hr ); + ok( codep == NULL, "codep != NULL\n" ); + + hr = set_input( reader, badxml, strlen(badxml) ); + ok( hr == S_OK, "got %#lx\n", hr ); + hr = WsReadXmlBuffer( reader, heap, &fault.detail, NULL ); + ok( hr == S_OK, "got %#lx\n", hr ); + hr = WsSetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_FAULT, &fault, sizeof(fault) ); + ok( hr == S_OK, "got %#lx\n", hr ); + + hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_REQUIRED_VALUE, heap, &code, sizeof(code) ); + ok( hr == WS_E_INVALID_FORMAT, "got %#lx\n", hr ); + + hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_REQUIRED_POINTER, heap, &codep, sizeof(codep) ); + ok( hr == WS_E_INVALID_FORMAT, "got %#lx\n", hr ); + + codep = (UINT32 *)0xdeadbeef; + hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_OPTIONAL_POINTER, heap, &codep, sizeof(codep) ); + ok( hr == WS_E_INVALID_FORMAT, "got %#lx\n", hr ); + ok( codep == NULL, "codep != NULL\n" ); + + codep = (UINT32 *)0xdeadbeef; + hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_NILLABLE_POINTER, heap, &codep, sizeof(codep) ); + ok( hr == WS_E_INVALID_FORMAT, "got %#lx\n", hr ); + ok( codep == NULL, "codep != NULL\n" ); + + WsFreeReader( reader ); + WsFreeHeap( heap ); + WsFreeError( error ); +} + START_TEST(reader) { test_WsCreateError(); @@ -7174,4 +7482,6 @@ START_TEST(reader) test_stream_input(); test_description_type(); test_WsAddErrorString(); + test_WsSetFaultErrorProperty(); + test_WsGetFaultErrorDetail(); } diff --git a/dlls/webservices/webservices.spec b/dlls/webservices/webservices.spec index 679d294ec1c..df28d71950a 100644 --- a/dlls/webservices/webservices.spec +++ b/dlls/webservices/webservices.spec @@ -64,8 +64,8 @@ @ stdcall WsGetDictionary(long ptr ptr) @ stdcall WsGetErrorProperty(ptr long ptr long) @ stdcall WsGetErrorString(ptr long ptr) -@ stub WsGetFaultErrorDetail -@ stub WsGetFaultErrorProperty +@ stdcall WsGetFaultErrorDetail(ptr ptr ptr ptr ptr long) +@ stdcall WsGetFaultErrorProperty(ptr long ptr long) @ stdcall WsGetHeader(ptr long long long ptr ptr long ptr) @ stub WsGetHeaderAttributes @ stdcall WsGetHeapProperty(ptr long ptr long ptr) @@ -148,7 +148,7 @@ @ stdcall WsSetChannelProperty(ptr long ptr long ptr) @ stdcall WsSetErrorProperty(ptr long ptr long) @ stub WsSetFaultErrorDetail -@ stub WsSetFaultErrorProperty +@ stdcall WsSetFaultErrorProperty(ptr long ptr long) @ stdcall WsSetHeader(ptr long long long ptr long ptr) @ stdcall WsSetInput(ptr ptr ptr ptr long ptr) @ stdcall WsSetInputToBuffer(ptr ptr ptr long ptr) diff --git a/dlls/webservices/webservices_private.h b/dlls/webservices/webservices_private.h index 373ab6799a9..d7f62c3d8a6 100644 --- a/dlls/webservices/webservices_private.h +++ b/dlls/webservices/webservices_private.h @@ -171,6 +171,8 @@ HRESULT channel_get_reader( WS_CHANNEL *, WS_XML_READER ** ) DECLSPEC_HIDDEN;
HRESULT parse_url( const WS_STRING *, WS_URL_SCHEME_TYPE *, WCHAR **, USHORT * ) DECLSPEC_HIDDEN;
+void free_fault_fields( WS_HEAP *, WS_FAULT * ) DECLSPEC_HIDDEN; + enum record_type { /* 0x00 reserved */ diff --git a/include/webservices.h b/include/webservices.h index 9395ad6f0e3..6657ee84201 100644 --- a/include/webservices.h +++ b/include/webservices.h @@ -1116,6 +1116,41 @@ struct _WS_ENDPOINT_ADDRESS { WS_ENDPOINT_IDENTITY *identity; };
+typedef struct _WS_FAULT_CODE { + WS_XML_QNAME value; + struct _WS_FAULT_CODE *subCode; +} WS_FAULT_CODE; + +typedef struct _WS_FAULT_REASON { + WS_STRING text; + WS_STRING lang; +} WS_FAULT_REASON; + +typedef struct _WS_FAULT { + WS_FAULT_CODE *code; + WS_FAULT_REASON *reasons; + ULONG reasonCount; + WS_STRING actor; + WS_STRING node; + WS_XML_BUFFER *detail; +} WS_FAULT; + +typedef struct _WS_FAULT_DESCRIPTION { + WS_ENVELOPE_VERSION envelopeVersion; +} WS_FAULT_DESCRIPTION; + +typedef struct _WS_FAULT_DETAIL_DESCRIPTION { + WS_XML_STRING *action; + WS_ELEMENT_DESCRIPTION *detailElementDescription; +} WS_FAULT_DETAIL_DESCRIPTION; + +typedef enum { + WS_FAULT_ERROR_PROPERTY_FAULT = 0, + WS_FAULT_ERROR_PROPERTY_ACTION = 1, + WS_FAULT_ERROR_PROPERTY_HEADER = 2 +} WS_FAULT_ERROR_PROPERTY_ID; + + struct _WS_HTTP_POLICY_DESCRIPTION { WS_CHANNEL_PROPERTIES channelProperties; }; @@ -1649,6 +1684,9 @@ HRESULT WINAPI WsGetCustomHeader(WS_MESSAGE*, const WS_ELEMENT_DESCRIPTION*, WS_ HRESULT WINAPI WsGetDictionary(WS_ENCODING, WS_XML_DICTIONARY**, WS_ERROR*); HRESULT WINAPI WsGetErrorProperty(WS_ERROR*, WS_ERROR_PROPERTY_ID, void*, ULONG); HRESULT WINAPI WsGetErrorString(WS_ERROR*, ULONG, WS_STRING*); +HRESULT WINAPI WsGetFaultErrorDetail(WS_ERROR*, const WS_FAULT_DETAIL_DESCRIPTION*, WS_READ_OPTION, + WS_HEAP*, void*, ULONG); +HRESULT WINAPI WsGetFaultErrorProperty(WS_ERROR*, WS_FAULT_ERROR_PROPERTY_ID, void*, ULONG); HRESULT WINAPI WsGetHeader(WS_MESSAGE*, WS_HEADER_TYPE, WS_TYPE, WS_READ_OPTION, WS_HEAP*, void*, ULONG, WS_ERROR*); HRESULT WINAPI WsGetHeapProperty(WS_HEAP*, WS_HEAP_PROPERTY_ID, void*, ULONG, WS_ERROR*); @@ -1731,6 +1769,7 @@ HRESULT WINAPI WsSendReplyMessage(WS_CHANNEL*, WS_MESSAGE*, const WS_MESSAGE_DES const WS_ASYNC_CONTEXT*, WS_ERROR*); HRESULT WINAPI WsSetChannelProperty(WS_CHANNEL*, WS_CHANNEL_PROPERTY_ID, const void*, ULONG, WS_ERROR*); HRESULT WINAPI WsSetErrorProperty(WS_ERROR*, WS_ERROR_PROPERTY_ID, const void*, ULONG); +HRESULT WINAPI WsSetFaultErrorProperty(WS_ERROR*, WS_FAULT_ERROR_PROPERTY_ID, const void*, ULONG); HRESULT WINAPI WsSetHeader(WS_MESSAGE*, WS_HEADER_TYPE, WS_TYPE, WS_WRITE_OPTION, const void*, ULONG, WS_ERROR*); HRESULT WINAPI WsSetInput(WS_XML_READER*, const WS_XML_READER_ENCODING*, const WS_XML_READER_INPUT*,
On Tue Aug 2 20:49:17 2022 +0000, Hans Leidekker wrote:
Otherwise this patchset looks good.
Thanks! I have addressed all comments.
This merge request was approved by Hans Leidekker.