示例#1
0
文件: msg.c 项目: bdidemus/wine
/**************************************************************************
 *          WsWriteBody		[webservices.@]
 */
HRESULT WINAPI WsWriteBody( WS_MESSAGE *handle, const WS_ELEMENT_DESCRIPTION *desc, WS_WRITE_OPTION option,
                            const void *value, ULONG size, WS_ERROR *error )
{
    struct msg *msg = (struct msg *)handle;
    HRESULT hr;

    TRACE( "%p %p %08x %p %u %p\n", handle, desc, option, value, size, error );
    if (error) FIXME( "ignoring error parameter\n" );

    if (!handle || !desc) return E_INVALIDARG;
    if (msg->state != WS_MESSAGE_STATE_WRITING) return WS_E_INVALID_OPERATION;

    if (desc->elementLocalName &&
        (hr = WsWriteStartElement( msg->writer_body, NULL, desc->elementLocalName, desc->elementNs,
                                   NULL )) != S_OK) return hr;

    if ((hr = WsWriteType( msg->writer_body, WS_ANY_ELEMENT_TYPE_MAPPING, desc->type, desc->typeDescription,
                           option, value, size, NULL )) != S_OK) return hr;

    if (desc->elementLocalName) hr = WsWriteEndElement( msg->writer_body, NULL );
    return hr;
}
示例#2
0
文件: msg.c 项目: bdidemus/wine
static HRESULT write_envelope_start( struct msg *msg, WS_XML_WRITER *writer )
{
    static const char anonymous[] = "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous";
    WS_XML_STRING prefix_s = {1, (BYTE *)"s"}, prefix_a = {1, (BYTE *)"a"}, body = {4, (BYTE *)"Body"};
    WS_XML_STRING envelope = {8, (BYTE *)"Envelope"}, header = {6, (BYTE *)"Header"};
    WS_XML_STRING msgid = {9, (BYTE *)"MessageID"}, replyto = {7, (BYTE *)"ReplyTo"};
    WS_XML_STRING address = {7, (BYTE *)"Address"}, ns_env, ns_addr;
    WS_XML_UTF8_TEXT urn, addr;
    HRESULT hr;

    if ((hr = get_env_namespace( msg->version_env, &ns_env )) != S_OK) return hr;
    if ((hr = get_addr_namespace( msg->version_addr, &ns_addr )) != S_OK) return hr;

    if ((hr = WsWriteStartElement( writer, &prefix_s, &envelope, &ns_env, NULL )) != S_OK) return hr;
    if ((hr = WsWriteXmlnsAttribute( writer, &prefix_a, &ns_addr, FALSE, NULL )) != S_OK) return hr;
    if ((hr = WsWriteStartElement( writer, &prefix_s, &header, &ns_env, NULL )) != S_OK) return hr;
    if ((hr = WsWriteStartElement( writer, &prefix_a, &msgid, &ns_addr, NULL )) != S_OK) return hr;

    urn.text.textType = WS_XML_TEXT_TYPE_UNIQUE_ID;
    memcpy( &urn.value, &msg->id, sizeof(msg->id) );
    if ((hr = WsWriteText( writer, &urn.text, NULL )) != S_OK) return hr;

    if ((hr = WsWriteEndElement( writer, NULL )) != S_OK) return hr; /* </a:MessageID> */
    if (msg->version_addr == WS_ADDRESSING_VERSION_0_9)
    {
        if ((hr = WsWriteStartElement( writer, &prefix_a, &replyto, &ns_addr, NULL )) != S_OK) return hr;
        if ((hr = WsWriteStartElement( writer, &prefix_a, &address, &ns_addr, NULL )) != S_OK) return hr;

        addr.text.textType = WS_XML_TEXT_TYPE_UTF8;
        addr.value.bytes   = (BYTE *)anonymous;
        addr.value.length  = sizeof(anonymous) - 1;
        if ((hr = WsWriteText( writer, &addr.text, NULL )) != S_OK) return hr;
        if ((hr = WsWriteEndElement( writer, NULL )) != S_OK) return hr; /* </a:Address> */
        if ((hr = WsWriteEndElement( writer, NULL )) != S_OK) return hr; /* </a:ReplyTo> */
    }

    if ((hr = WsWriteEndElement( writer, NULL )) != S_OK) return hr; /* </s:Header> */
    return WsWriteStartElement( writer, &prefix_s, &body, &ns_env, NULL ); /* <s:Body> */
}
// Reads the data and serializes it into the message. This function does custom serialization for the same
// reason and with the same alrogithm as DeserializeAndWriteMessage.
HRESULT CFileRepServer::ReadAndSendChunk(
    __in CRequest* request,
    __in long chunkSize, 
    __in LONGLONG chunkPosition,
    __in HANDLE file)
{
    PrintVerbose(L"Entering CFileRepServer::ReadAndSendChunk");

    if (chunkSize < 0 || chunkPosition < 0)
    {
        PrintVerbose(L"Leaving CFileRepServer::ReadAndSendChunk");
        return E_INVALIDARG;
    }

    HRESULT hr = S_OK;
    WS_XML_WRITER* writer = NULL;
    WS_MESSAGE* replyMessage = request->GetReplyMessage();
    WS_MESSAGE* requestMessage = request->GetRequestMessage();
    WS_ERROR* error = request->GetError();
    WS_CHANNEL* channel = request->GetChannel();

    BYTE* buf = NULL;
    LONG length = 0;

    // To avoid using too much memory we read and write the message in chunks.
    LONG bytesToRead = FILE_CHUNK;
    if (bytesToRead > chunkSize)
    {
        bytesToRead = chunkSize;
    }

    buf = (BYTE*)HeapAlloc(GetProcessHeap(), 0, bytesToRead);
    IfNullExit(buf);

    IfFailedExit(WsInitializeMessage(replyMessage, WS_BLANK_MESSAGE, requestMessage, error));

    // Add the action header
    IfFailedExit(WsSetHeader(
        replyMessage,
        WS_ACTION_HEADER,
        WS_XML_STRING_TYPE,
        WS_WRITE_REQUIRED_VALUE,
        &fileReplyAction,
        sizeof(fileReplyAction),
        error));

    // Send the message headers
    IfFailedExit(WsWriteMessageStart(channel, replyMessage, NULL, error));

    // Get writer to serialize message body
    IfFailedExit(WsGetMessageProperty(replyMessage, WS_MESSAGE_PROPERTY_BODY_WRITER, &writer, sizeof(writer), error));

    // Write FileChunk start element.
    // This whole code block is the serialization equivalent of the desiralization code.
    IfFailedExit(WsWriteStartElement(writer, NULL, &fileChunkLocalName, &fileChunkNamespace, error));

    // Write chunkPosition element
    IfFailedExit(WsWriteStartElement(writer, NULL, &chunkPositionLocalName, &fileChunkNamespace, error));
    IfFailedExit(WsWriteValue(writer, WS_INT64_VALUE_TYPE, &chunkPosition, sizeof(chunkPosition), error));
    IfFailedExit(WsWriteEndElement(writer, error));

    // Write fileContent start element
    IfFailedExit(WsWriteStartElement(writer, NULL, &fileContentLocalName, &fileChunkNamespace, error));

    // Like in the deserialization code, we read the file in multiple steps to avoid
    // having to have everything in memory at once. The message could potentially be
    // big so this is more efficient.
    for (;;)
    {
        ULONG bytesRead = 0;

        if (length + bytesToRead > chunkSize)
        {
            bytesToRead = chunkSize - length;
        }

        if (!ReadFile(file, buf, bytesToRead, &bytesRead, NULL))
        {

            PrintError(L"File read error.", true);
            hr = HRESULT_FROM_WIN32(GetLastError());

            EXIT_FUNCTION
        }

        if (0 == bytesRead)
        {
            // We reched the end of the file before filling the chunk. Send a partial chunk.
            break;
        }

        IfFailedExit(WsWriteBytes(writer, buf, bytesRead, error));

        length += bytesRead;

        if (length == chunkSize)
        {
            // We filled the message
            break;
        }
    }
        IfFailedExit(WsWriteBytes(writer, buf, bytesRead, error));

        length += bytesRead;

        if (length == chunkSize)
        {
            // We filled the message
            break;
        }
    }

    // Write fileContent end element
    IfFailedExit(WsWriteEndElement(writer, error));

    // Write error element
    IfFailedExit(WsWriteStartElement(writer, NULL, &errorLocalName, &fileChunkNamespace, error));
    const WCHAR* noError = GlobalStrings::noError;
    IfFailedExit(WsWriteType(
        writer,
        WS_ELEMENT_TYPE_MAPPING,
        WS_WSZ_TYPE,
        NULL,
        WS_WRITE_REQUIRED_POINTER,
        &noError,
        sizeof(noError),
        error));

    // Closing elements;
    IfFailedExit(WsWriteEndElement(writer, error));
    IfFailedExit(WsWriteEndElement(writer, error));
    IfFailedExit(WsWriteMessageEnd(channel, replyMessage, NULL, error));
// Main entry point
int __cdecl wmain()
{
    
    HRESULT hr = S_OK;
    WS_ERROR* error = NULL;
    WS_XML_WRITER* writer = NULL;
    WS_XML_READER* reader = NULL;
    WS_HEAP* heap = NULL;
    
    // Create an error object for storing rich error information
    hr = WsCreateError(
        NULL, 
        0, 
        &error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    // Create a heap to store deserialized data
    hr = WsCreateHeap(
        /*maxSize*/ 2048, 
        /*trimSize*/ 512, 
        NULL, 
        0, 
        &heap, 
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    // Create an XML writer
    hr = WsCreateWriter(
        NULL, 
        0, 
        &writer, 
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    // Setup the output
    WS_XML_WRITER_BUFFER_OUTPUT bufferOutput;
    ZeroMemory(&bufferOutput, sizeof(bufferOutput));
    bufferOutput.output.outputType = WS_XML_WRITER_OUTPUT_TYPE_BUFFER;
    
    // Setup the encoding
    WS_XML_WRITER_BINARY_ENCODING writerEncoding;
    ZeroMemory(&writerEncoding, sizeof(writerEncoding));
    writerEncoding.encoding.encodingType = WS_XML_WRITER_ENCODING_TYPE_BINARY;
    writerEncoding.staticDictionary = &objectsDictionary.dictionary;
    writerEncoding.dynamicStringCallback = DynamicStringCallback;
    writerEncoding.dynamicStringCallbackState = NULL;
    
    // Setup the writer
    hr = WsSetOutput(
        writer, 
        &writerEncoding.encoding, 
        &bufferOutput.output, 
        NULL, 
        0, 
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    hr = WsWriteStartElement(
        writer, 
        NULL, 
        &objectsDictionary.objects, 
        &objectsDictionary.ns, 
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    // Write some xml using strings from all the dictionaries
    static const WS_XML_STRING* shapes[3] = { &shapeDictionary.triangle, &shapeDictionary.square, &shapeDictionary.circle };
    static const WS_XML_STRING* colors[3] = { &colorDictionary.green, &colorDictionary.blue, &colorDictionary.red };
    for (ULONG i = 0; i < 3; i++)
    {
        hr = WsWriteStartElement(
            writer, 
            NULL, 
            shapes[i], 
            &objectsDictionary.ns, 
            error);
        if (FAILED(hr))
        {
            goto Exit;
        }
    
        hr = WsWriteStartAttribute(
            writer, 
            NULL, 
            &objectsDictionary.color, 
            &objectsDictionary.ns, 
            FALSE, 
            error);
        if (FAILED(hr))
        {
            goto Exit;
        }
    
        hr = WsWriteType(
            writer, 
            WS_ATTRIBUTE_TYPE_MAPPING, 
            WS_XML_STRING_TYPE, NULL, 
            WS_WRITE_REQUIRED_VALUE, 
            colors[i], 
            sizeof(*colors[i]), 
            error);
        if (FAILED(hr))
        {
            goto Exit;
        }
    
        hr = WsWriteEndAttribute(
            writer, 
            error);
        if (FAILED(hr))
        {
            goto Exit;
        }
    
        hr = WsWriteEndElement(
            writer, 
            error);
        if (FAILED(hr))
        {
            goto Exit;
        }
    }
    
    hr = WsWriteEndElement(
        writer, 
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    WS_BYTES bytes;
    hr = WsGetWriterProperty(
        writer, 
        WS_XML_WRITER_PROPERTY_BYTES, 
        &bytes, 
        sizeof(bytes), 
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    // Create an XML reader
    hr = WsCreateReader(
        NULL,
        0, 
        &reader, 
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    // Setup the input
    WS_XML_READER_BUFFER_INPUT bufferInput;
    ZeroMemory(&bufferInput, sizeof(bufferInput));
    bufferInput.input.inputType = WS_XML_READER_INPUT_TYPE_BUFFER;
    bufferInput.encodedData = bytes.bytes;
    bufferInput.encodedDataSize = bytes.length;
    
    // Setup the encoding
    WS_XML_READER_BINARY_ENCODING readerEncoding;
    ZeroMemory(
        &readerEncoding, 
        sizeof(readerEncoding));
    
    readerEncoding.encoding.encodingType = WS_XML_READER_ENCODING_TYPE_BINARY;
    readerEncoding.staticDictionary = &objectsDictionary.dictionary;
    readerEncoding.dynamicDictionary = &mergedDictionary.dictionary;
    
    // Setup the reader
    hr = WsSetInput(
        reader, 
        &readerEncoding.encoding, 
        &bufferInput.input, 
        NULL, 
        0, 
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    hr = WsReadToStartElement(
        reader, 
        &objectsDictionary.objects, 
        &objectsDictionary.ns, 
        NULL, 
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    hr = WsReadStartElement(
        reader, 
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    for (;;)
    {
        BOOL found;
        hr = WsReadToStartElement(
            reader, 
            NULL, 
            NULL, 
            &found, 
            error);
        if (FAILED(hr))
        {
            goto Exit;
        }
    
        if (!found)
        {
            break;
        }
    
        const WS_XML_NODE* node;
        hr = WsGetReaderNode(
            reader, 
            &node, 
            error);
        if (FAILED(hr))
        {
            goto Exit;
        }
    
        const WS_XML_ELEMENT_NODE* elementNode = (WS_XML_ELEMENT_NODE*)node;
        printf("%.*s: ", elementNode->localName->length, elementNode->localName->bytes);
    
        ULONG index;
        hr = WsFindAttribute(
            reader, 
            &objectsDictionary.color, 
            &objectsDictionary.ns, 
            TRUE, 
            &index, 
            error);
        if (FAILED(hr))
        {
            goto Exit;
        }
    
        hr = WsReadStartAttribute(
            reader, 
            index, 
            error);
        if (FAILED(hr))
        {
            goto Exit;
        }
    
        WS_XML_STRING color;
        hr = WsReadType(
            reader, 
            WS_ATTRIBUTE_TYPE_MAPPING, 
            WS_XML_STRING_TYPE, 
            NULL, 
            WS_READ_REQUIRED_VALUE, 
            heap, 
            &color, 
            sizeof(color), 
            error);
        if (FAILED(hr))
        {
            goto Exit;
        }
    
        printf(
            "%.*s\n", 
            color.length, 
            color.bytes);
    
        hr = WsReadEndAttribute(
            reader, 
            error);
        if (FAILED(hr))
        {
            goto Exit;
        }
        
        hr = WsSkipNode(
            reader, 
            error);
        if (FAILED(hr))
        {
            goto Exit;
        }
    }
    
    hr = WsReadEndElement(
        reader, 
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
Exit:
    if (FAILED(hr))
    {
        // Print out the error
        PrintError(hr, error);
    }
    
    if (writer != NULL)
    {
        WsFreeWriter(writer);
    }
    if (reader != NULL)
    {
        WsFreeReader(reader);
    }
    if (heap != NULL)
    {
        WsFreeHeap(heap);
    }
    if (error != NULL)
    {
        WsFreeError(error);
    }
    fflush(stdout);
    return SUCCEEDED(hr) ? 0 : -1;
}
// Main entry point
int __cdecl wmain()
{
    
    HRESULT hr = S_OK;
    WS_ERROR* error = NULL;
    WS_XML_BUFFER* xmlBuffer = NULL;
    WS_HEAP* heap = NULL;
    WS_XML_READER* xmlReader = NULL;
    WS_XML_WRITER* xmlWriter = NULL;
    PayloadBaseType* baseType = NULL;
    Payload1Type* payload1Type = NULL;
    
    static const WS_XML_STRING dataElement = WS_XML_STRING_VALUE("data");
    static const WS_XML_STRING emptyNamespace = WS_XML_STRING_VALUE("");
    
    // Create an error object for storing rich error information
    hr = WsCreateError(
        NULL, 
        0, 
        &error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    // Create a heap to store deserialized data
    hr = WsCreateHeap(
        /*maxSize*/ 4096,
        /*trimSize*/ 512,
        NULL,
        0,
        &heap,
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    // Create an XML reader
    hr = WsCreateReader(
        NULL,
        0, 
        &xmlReader, 
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    // Create an XML writer
    hr = WsCreateWriter(
        NULL, 
        0, 
        &xmlWriter, 
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    // Create an XML buffer on the specified heap
    hr = WsCreateXmlBuffer(
        heap, 
        NULL, 
        0, 
        &xmlBuffer, 
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    // Set the writer to output to the XML buffer
    hr = WsSetOutputToBuffer(
        xmlWriter, 
        xmlBuffer, 
        NULL, 
        0, 
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    // Create a wrapper element for the two embedded elements
    hr = WsWriteStartElement(
        xmlWriter,
        NULL,
        &dataElement,
        &emptyNamespace,
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    baseType = new(std::nothrow) PayloadBaseType();
    if (baseType == NULL)
    {
        goto Exit;
    }
    baseType->Id = 1;
    
    payload1Type = new(std::nothrow) Payload1Type();
    if (payload1Type == NULL)
    {
        goto Exit;
    }
    payload1Type->Id = 2;
    payload1Type->BoolValue = FALSE;
    payload1Type->StringValue = L"hello world";
    // Write the base type using the element description of the base type.
    // An xsi:type attribute will be added to the XML document for the element
    // indicating this is the base type.
    hr = WsWriteElement(
        xmlWriter,
        &DerivedType_xsd.globalElements.PayloadBase,
        WS_WRITE_REQUIRED_VALUE,
        baseType,
        sizeof(PayloadBaseType),
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    // Write the derived type using the element description of the base type.
    // An xsi:type attribute will be added to the XML document for the element
    // indicating this is the derived type.
    hr = WsWriteElement(
        xmlWriter,
        &DerivedType_xsd.globalElements.PayloadBase,
        WS_WRITE_REQUIRED_VALUE,
        payload1Type,
        sizeof(Payload1Type),
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    hr = WsWriteEndElement(
        xmlWriter,
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    // Flush writer so all XML content is put in the buffer
    hr = WsFlushWriter(xmlWriter, 0, NULL, error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    // Set the reader input to current position of XML buffer
    hr = WsSetInputToBuffer(xmlReader, xmlBuffer, NULL, 0, error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    // Read pass the wrapper element
    hr = WsReadToStartElement(
        xmlReader,
        &dataElement,
        &emptyNamespace,
        NULL,
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    
    hr = WsReadStartElement(
        xmlReader,
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    PayloadBaseType* outBaseType = NULL;
    
    // Read the first element using element description for the base
    // type. The type of returning structure is that of that base type.
    hr = WsReadElement(
        xmlReader,
        &DerivedType_xsd.globalElements.PayloadBase,
        WS_READ_REQUIRED_POINTER,
        heap,
        &outBaseType,
        sizeof(PayloadBaseType*),
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    PrintPayloadType(outBaseType);
    
    // Read the second element using element description for the base
    // type. The type of returning structure is that of the derived type.
    hr = WsReadElement(
        xmlReader,
        &DerivedType_xsd.globalElements.PayloadBase,
        WS_READ_REQUIRED_POINTER,
        heap,
        &outBaseType,
        sizeof(PayloadBaseType*),
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    PrintPayloadType(outBaseType);
    
    hr = WsReadEndElement(
        xmlReader,
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
Exit:
    if (FAILED(hr))
    {
        // Print out the error
        PrintError(hr, error);
    }
    
    delete baseType;
    delete payload1Type;
    
    if (xmlReader != NULL)
    {
        WsFreeReader(xmlReader);
    }
    if (xmlWriter != NULL)
    {
        WsFreeWriter(xmlWriter);
    }
    if (error != NULL)
    {
        WsFreeError(error);
    }
    if (heap != NULL)
    {
        WsFreeHeap(heap);
    }
    
    fflush(stdout);
    return SUCCEEDED(hr) ? 0 : -1;
}
// Main entry point
int __cdecl wmain()
{
    
    HRESULT hr = S_OK;
    WS_ERROR* error = NULL;
    WS_HEAP* heap = NULL;
    WS_XML_BUFFER* buffer = NULL;
    WS_XML_WRITER* writer = NULL;
    WS_XML_READER* reader = NULL;
    void* xml = NULL;
    ULONG xmlLength = 0;
    WS_XML_NODE_POSITION securityEndElementPosition;
    
    static const WS_XML_STRING soapNs = WS_XML_STRING_VALUE("http://schemas.xmlsoap.org/soap/envelope/");
    static const WS_XML_STRING wsseNs = WS_XML_STRING_VALUE("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
    static const WS_XML_STRING envelope = WS_XML_STRING_VALUE("Envelope");
    static const WS_XML_STRING header = WS_XML_STRING_VALUE("Header");
    static const WS_XML_STRING security = WS_XML_STRING_VALUE("Security");
    static const WS_XML_STRING dsNs = WS_XML_STRING_VALUE("http://www.w3.org/2000/09/xmldsig#");
    static const WS_XML_STRING signature = WS_XML_STRING_VALUE("Signature");
    
    // Create an error object for storing rich error information
    hr = WsCreateError(
        NULL, 
        0, 
        &error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    // Create a heap to store deserialized data
    hr = WsCreateHeap(
        /*maxSize*/ 2048, 
        /*trimSize*/ 512, 
        NULL, 
        0, 
        &heap, 
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    // Create an XML writer
    hr = WsCreateWriter(
        NULL, 
        0, 
        &writer, 
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    // Create an XML reader
    hr = WsCreateReader(
        NULL,
        0, 
        &reader, 
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    // Create an XML buffer on the specified heap
    hr = WsCreateXmlBuffer(
        heap, 
        NULL, 
        0, 
        &buffer, 
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    // Set the writer to output to the XML buffer
    hr = WsSetOutputToBuffer(
        writer, 
        buffer, 
        NULL, 
        0, 
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    // Write the envelope element
    hr = WsWriteStartElement(writer, NULL, &envelope, &soapNs, error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    // Write the header element
    hr = WsWriteStartElement(writer, NULL, &header, &soapNs, error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    // Write the security element
    hr = WsWriteStartElement(writer, NULL, &security, &wsseNs, error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    // Force the security element start tag to be written so the position obtained
    // is "after" the security element
    hr = WsWriteEndStartElement(writer, error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    hr = WsGetWriterPosition(writer, &securityEndElementPosition, error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    // Close the security element
    hr = WsWriteEndElement(writer, error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    // Close the header element
    hr = WsWriteEndElement(writer, error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    // Close the envelope element
    hr = WsWriteEndElement(writer, error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    // Move the write back
    hr = WsSetWriterPosition(writer, &securityEndElementPosition, error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    // Write the "signature" element
    hr = WsWriteStartElement(writer, NULL, &signature, &dsNs, error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    // Close the signature element
    hr = WsWriteEndElement(writer, error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    // Generate the bytes of the document
    ULONG indent = 4;
    WS_XML_WRITER_PROPERTY properties[1];
    properties[0].id = WS_XML_WRITER_PROPERTY_INDENT;
    properties[0].value = &indent;
    properties[0].valueSize = sizeof(indent);
    hr = WsWriteXmlBufferToBytes(writer, buffer, NULL, properties, WsCountOf(properties), heap, &xml, &xmlLength, error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    printf("%.*s\n", xmlLength, (char*)xml);
    
Exit:
    if (FAILED(hr))
    {
        // Print out the error
        PrintError(hr, error);
    }
    
    if (writer != NULL)
    {
        WsFreeWriter(writer);
    }
    if (reader != NULL)
    {
        WsFreeReader(reader);
    }
    if (heap != NULL)
    {
        WsFreeHeap(heap);
    }
    if (error != NULL)
    {
        WsFreeError(error);
    }
    fflush(stdout);
    return SUCCEEDED(hr) ? 0 : -1;
}