903 lines
22 KiB
C++
903 lines
22 KiB
C++
//////////////////////////////////////////////////////////////////////////////
|
|
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
// PARTICULAR PURPOSE.
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include <winsock2.h>
|
|
#include <windows.h>
|
|
#include <stdlib.h>
|
|
#include <strsafe.h>
|
|
#include <string.h>
|
|
#include <wsdapi.h>
|
|
#include "Common.h"
|
|
|
|
#define TEMP_HOST_NAME_LENGTH 80 // length of temporary host name
|
|
|
|
// length of temporary guid string
|
|
// 0 1 2 3
|
|
// 123456789012345678901234567890123456 +1 for NULL char
|
|
// 91022ed0-7d3d-11de-8a39-0800200c9a66
|
|
#define TEMP_GUID_STRING_LENGTH 37
|
|
|
|
// helper method for DeepCopyString and DeepCopyStringLinked
|
|
// - they both have similar routines, except that DeepCopyString
|
|
// allocates memory using the "new" keyword, and DeepCopyStringLinked
|
|
// uses WSDAllocateLinkedMemory to allocate memory for the string and links
|
|
// it to the specified parent
|
|
_Success_( return == S_OK )
|
|
static HRESULT _DeepCopyStringHelper
|
|
( _In_ BOOL isLinked
|
|
, _In_ LPCWSTR source
|
|
, _In_opt_ void *parent
|
|
, _Outptr_ LPWSTR *dest
|
|
);
|
|
|
|
HRESULT DeepCopyString
|
|
( _In_ LPCWSTR source
|
|
, _Outptr_ LPWSTR *dest
|
|
)
|
|
{
|
|
return _DeepCopyStringHelper( FALSE, source, NULL, dest );
|
|
}
|
|
|
|
HRESULT DeepCopyStringLinked
|
|
( _In_ LPCWSTR source
|
|
, _In_opt_ void *parent
|
|
, _Outptr_ LPWSTR *dest
|
|
)
|
|
{
|
|
return _DeepCopyStringHelper( TRUE, source, parent, dest );
|
|
}
|
|
|
|
_Success_( return == S_OK )
|
|
HRESULT _DeepCopyStringHelper
|
|
( _In_ BOOL isLinked
|
|
, _In_ LPCWSTR source
|
|
, _In_opt_ void *parent
|
|
, _Outptr_ LPWSTR *dest
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
size_t stringLength = 0;
|
|
LPWSTR tempDest = NULL;
|
|
|
|
if ( NULL == source )
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
else if ( NULL == dest )
|
|
{
|
|
hr = E_POINTER;
|
|
}
|
|
else
|
|
{
|
|
*dest = NULL;
|
|
}
|
|
|
|
if ( S_OK == hr )
|
|
{
|
|
// determine length of source string
|
|
stringLength = wcslen(source);
|
|
}
|
|
|
|
if ( S_OK == hr )
|
|
{
|
|
// num char = stringLength + 1 (for NULL char)
|
|
if ( isLinked )
|
|
{
|
|
tempDest = (WCHAR *)WSDAllocateLinkedMemory(
|
|
parent, sizeof( WCHAR ) * ( stringLength + 1 ) );
|
|
}
|
|
else
|
|
{
|
|
tempDest = new WCHAR[stringLength + 1];
|
|
}
|
|
|
|
if ( NULL == tempDest )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
if ( S_OK == hr )
|
|
{
|
|
// deep copy string
|
|
hr = StringCchCopyW( tempDest, stringLength + 1, source );
|
|
}
|
|
|
|
if ( S_OK == hr )
|
|
{
|
|
// outside pointer now owns the temp string
|
|
*dest = tempDest;
|
|
tempDest = NULL;
|
|
}
|
|
|
|
if ( NULL != tempDest )
|
|
{
|
|
if ( isLinked )
|
|
{
|
|
WSDFreeLinkedMemory( tempDest );
|
|
}
|
|
else
|
|
{
|
|
delete[] tempDest;
|
|
}
|
|
|
|
tempDest = NULL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
_Success_( return == S_OK )
|
|
HRESULT GetWideStringHostName
|
|
( _Outptr_ LPWSTR *hostName
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPWSTR tempHostName = NULL;
|
|
WSADATA wsaData = {0};
|
|
int returnCode = 0;
|
|
size_t stringLength = 0;
|
|
WORD versionRequested = 0;
|
|
char asciiHostName[TEMP_HOST_NAME_LENGTH] = {0};
|
|
BOOL isWinsockStarted = FALSE;
|
|
|
|
if ( NULL == hostName )
|
|
{
|
|
hr = E_POINTER;
|
|
}
|
|
else
|
|
{
|
|
*hostName = NULL;
|
|
}
|
|
|
|
if ( S_OK == hr )
|
|
{
|
|
// use v2.2 for Windows XP and above
|
|
versionRequested = MAKEWORD( 2, 2 );
|
|
returnCode = WSAStartup( versionRequested, &wsaData );
|
|
|
|
if ( 0 != returnCode )
|
|
{
|
|
// no usable winsock dll available
|
|
hr = HRESULT_FROM_WIN32( (DWORD)WSAGetLastError() );
|
|
}
|
|
else
|
|
{
|
|
isWinsockStarted = TRUE;
|
|
}
|
|
}
|
|
|
|
if ( S_OK == hr )
|
|
{
|
|
// get the host name in ascii string
|
|
#pragma prefast( suppress: 38026, "This sample uses ASCII version of host names only for simplicity." )
|
|
returnCode = gethostname( asciiHostName, sizeof( asciiHostName ) );
|
|
|
|
if ( 0 != returnCode )
|
|
{
|
|
// failed to retrieve host name
|
|
hr = HRESULT_FROM_WIN32( (DWORD)WSAGetLastError() );
|
|
}
|
|
}
|
|
if ( S_OK == hr )
|
|
{
|
|
// create enough memory allocation for the wide string host name
|
|
stringLength = strlen( asciiHostName );
|
|
tempHostName = new WCHAR[stringLength + 1]; // + 1 for NULL char
|
|
|
|
if ( NULL == tempHostName )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
if ( S_OK == hr )
|
|
{
|
|
// convert the host name from ascii string to unicode string
|
|
hr = StringCchPrintfW( tempHostName, stringLength + 1, L"%S", asciiHostName );
|
|
}
|
|
|
|
if ( S_OK == hr )
|
|
{
|
|
// ensure that the last char is NULL
|
|
tempHostName[stringLength] = L'\0';
|
|
|
|
// outside pointer now owns the temp host name
|
|
*hostName = tempHostName;
|
|
tempHostName = NULL;
|
|
}
|
|
|
|
if ( isWinsockStarted )
|
|
{
|
|
(void)WSACleanup(); // don't care about the return code
|
|
}
|
|
|
|
if ( NULL != tempHostName )
|
|
{
|
|
delete[] tempHostName;
|
|
tempHostName = NULL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
_Success_( return == S_OK )
|
|
HRESULT DeepCopyWsdUriList
|
|
( _In_ const WSD_URI_LIST *srcList
|
|
, _Outptr_ WSD_URI_LIST **destList
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
WSD_URI_LIST *duplicatedList = NULL;
|
|
WSD_URI_LIST *tempList = NULL; // soft copy of current node for iteration - do not delete
|
|
|
|
if ( NULL == srcList )
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
else if ( NULL == destList )
|
|
{
|
|
hr = E_POINTER;
|
|
}
|
|
else
|
|
{
|
|
*destList = NULL;
|
|
}
|
|
|
|
while ( S_OK == hr && NULL != srcList )
|
|
{
|
|
if ( NULL == duplicatedList )
|
|
{
|
|
// first node to be duplicated - create the first node in the list
|
|
duplicatedList = (WSD_URI_LIST *)WSDAllocateLinkedMemory( NULL, sizeof( WSD_URI_LIST ) );
|
|
|
|
if ( NULL == duplicatedList )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
// use the temp list for subsequent nodes
|
|
tempList = duplicatedList;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// subsequent nodes - create the next node
|
|
tempList->Next = (WSD_URI_LIST *)WSDAllocateLinkedMemory(
|
|
tempList, // parent
|
|
sizeof( WSD_URI_LIST ) ); // child
|
|
|
|
if ( NULL == tempList->Next )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
tempList = tempList->Next;
|
|
}
|
|
}
|
|
|
|
if ( S_OK == hr )
|
|
{
|
|
// initialize the node
|
|
tempList->Element = NULL;
|
|
tempList->Next = NULL;
|
|
|
|
// copy the uri string
|
|
hr = DeepCopyStringLinked(
|
|
srcList->Element,
|
|
tempList, // parent
|
|
const_cast<LPWSTR*>( &(tempList->Element) ) ); // child
|
|
}
|
|
|
|
if ( S_OK == hr )
|
|
{
|
|
// move to next node
|
|
srcList = srcList->Next;
|
|
}
|
|
}
|
|
|
|
if ( S_OK == hr )
|
|
{
|
|
// outside pointer now owns the duplicated list
|
|
*destList = duplicatedList;
|
|
duplicatedList = NULL;
|
|
}
|
|
|
|
if ( NULL != tempList )
|
|
{
|
|
tempList = NULL; // do not delete
|
|
}
|
|
|
|
if ( NULL != duplicatedList )
|
|
{
|
|
WSDFreeLinkedMemory( duplicatedList );
|
|
duplicatedList = NULL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
_Success_( return == S_OK )
|
|
HRESULT ParseScopes
|
|
( _In_ int argc
|
|
, _In_reads_( argc ) LPWSTR *argv
|
|
, _In_ int startIndex
|
|
, _Outptr_result_maybenull_ WSD_URI_LIST **scopesList
|
|
)
|
|
{
|
|
// Create linked list of scopes.
|
|
//
|
|
// Here is a quick overview of how we use linked memory here,
|
|
// and how we useWSDAttachLinkedMemory and WSDFreeLinkedMemory
|
|
// to accomplish this.
|
|
//
|
|
// Example:
|
|
// tempScopeList [WSD_URI_LIST - top level parent (i.e. parent: NULL)]
|
|
// --> Element: string1 (parent: tempScopeList - this node owns the string)
|
|
// --> Next: tempScopeList2 (parent: tempScopeList - this node owns the next node)
|
|
// --> Element: string2 (parent: tempScopeList2)
|
|
// --> Next: tempScopeList3 (parent: tempScopeList2)
|
|
// --> Element: string3 (parent: tempScopeList3)
|
|
// --> Next: NULL
|
|
//
|
|
// If all of the above elements and nodes are allocated using
|
|
// WSDAttachLinkedMemory, you can use WSDFreeLinkedMemory to
|
|
// deallocate all of the above memory allocations in one function call
|
|
// rather than to have a for loop and delete them one by one.
|
|
|
|
HRESULT hr = S_OK;
|
|
WSD_URI_LIST *tempScopesList = NULL;
|
|
WSD_URI_LIST *parentNode = NULL; // do not deallocate
|
|
WSD_URI_LIST **nextNode = NULL; // do not deallocate
|
|
int i = 0; // for loop
|
|
|
|
if ( 1 > argc || NULL == argv ||
|
|
0 > startIndex || argc <= startIndex )
|
|
{
|
|
// Required conditions to pass:
|
|
// argc >= 1
|
|
// argv != NULL
|
|
// 0 <= startIndex < argc
|
|
hr = E_INVALIDARG;
|
|
}
|
|
else if ( NULL == scopesList )
|
|
{
|
|
hr = E_POINTER;
|
|
}
|
|
else
|
|
{
|
|
*scopesList = NULL;
|
|
}
|
|
|
|
nextNode = &tempScopesList;
|
|
parentNode = NULL;
|
|
|
|
for ( i = startIndex; i < argc && S_OK == hr; i++ )
|
|
{
|
|
// create the node in the memory of previous_node->next
|
|
*nextNode = (WSD_URI_LIST *)WSDAllocateLinkedMemory(
|
|
parentNode, sizeof( WSD_URI_LIST ) );
|
|
|
|
if ( NULL == *nextNode )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
if ( S_OK == hr )
|
|
{
|
|
(*nextNode)->Next = NULL;
|
|
|
|
// copy string to the node
|
|
_Analysis_assume_(NULL != *nextNode);
|
|
hr = DeepCopyStringLinked( argv[i], *nextNode,
|
|
const_cast<LPWSTR *>( &((*nextNode)->Element) ) );
|
|
}
|
|
|
|
if ( S_OK == hr )
|
|
{
|
|
// move to next node (memory wise)
|
|
parentNode = *nextNode;
|
|
nextNode = &((*nextNode)->Next);
|
|
}
|
|
}
|
|
|
|
// Do not deallocate nextNode and parentNode.
|
|
// Those references are held by tempScopesList.
|
|
nextNode = NULL;
|
|
parentNode = NULL;
|
|
|
|
if ( S_OK == hr )
|
|
{
|
|
// outside pointer now owns the list
|
|
*scopesList = tempScopesList;
|
|
tempScopesList = NULL;
|
|
}
|
|
|
|
if ( NULL != tempScopesList )
|
|
{
|
|
WSDFreeLinkedMemory( tempScopesList );
|
|
tempScopesList = NULL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
_Success_( return == S_OK )
|
|
HRESULT GetGuidString
|
|
( _In_ GUID guidToConvert
|
|
, _Outptr_ LPWSTR *guidString
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPWSTR tempGuidString = NULL;
|
|
|
|
if ( NULL == guidString )
|
|
{
|
|
hr = E_POINTER;
|
|
}
|
|
else
|
|
{
|
|
*guidString = NULL;
|
|
}
|
|
|
|
if ( S_OK == hr )
|
|
{
|
|
tempGuidString = new WCHAR[TEMP_GUID_STRING_LENGTH];
|
|
|
|
if ( NULL == tempGuidString )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
if ( S_OK == hr )
|
|
{
|
|
hr = StringCchPrintfW( tempGuidString, TEMP_GUID_STRING_LENGTH,
|
|
L"%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
|
|
guidToConvert.Data1, guidToConvert.Data2, guidToConvert.Data3,
|
|
guidToConvert.Data4[0], guidToConvert.Data4[1], guidToConvert.Data4[2],
|
|
guidToConvert.Data4[3], guidToConvert.Data4[4], guidToConvert.Data4[5],
|
|
guidToConvert.Data4[6], guidToConvert.Data4[7] );
|
|
}
|
|
|
|
if ( S_OK == hr )
|
|
{
|
|
// outside pointer now owns the temp string
|
|
*guidString = tempGuidString;
|
|
tempGuidString = NULL;
|
|
}
|
|
|
|
if ( NULL != tempGuidString )
|
|
{
|
|
delete[] tempGuidString;
|
|
tempGuidString = NULL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
void PrintGuid
|
|
( _In_ GUID guidToPrint
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPWSTR guidString = NULL;
|
|
|
|
// obtain the guid string
|
|
hr = GetGuidString( guidToPrint, &guidString );
|
|
|
|
if ( S_OK == hr )
|
|
{
|
|
wprintf( guidString );
|
|
}
|
|
else
|
|
{
|
|
PrintErrorMessage( L"Failed to print GUID string", hr );
|
|
}
|
|
|
|
if ( NULL != guidString )
|
|
{
|
|
delete[] guidString;
|
|
guidString = NULL;
|
|
}
|
|
}
|
|
|
|
void PrintErrorMessage
|
|
( _In_opt_ LPCWSTR message
|
|
, _In_ HRESULT hr
|
|
)
|
|
{
|
|
wprintf( L"%s: [0x%08X]\r\n", message, hr );
|
|
}
|
|
|
|
HRESULT PrintDiscoveredService
|
|
( _In_ IWSDiscoveredService *service
|
|
, _In_ BOOL isByeMessage
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPCWSTR probeResolveTag = NULL; // do not deallocate
|
|
WSD_ENDPOINT_REFERENCE *wsdEpr = NULL; // do not deallocate
|
|
ULONGLONG instanceId = 0;
|
|
WSD_NAME_LIST *typesList = NULL; // do not deallocate
|
|
WSD_URI_LIST *scopesList = NULL; // do not deallocate
|
|
WSD_URI_LIST *xAddrsList = NULL; // do not deallocate
|
|
ULONGLONG metadataVersion = 0;
|
|
LPCWSTR localAddress = NULL; // do not deallocate
|
|
LPCWSTR remoteAddress = NULL; // do not deallocate
|
|
GUID localGuid = { 0 };
|
|
WSDXML_ELEMENT *extendedXmlHeader = NULL; // do not deallocate
|
|
WSDXML_ELEMENT *extendedXmlBody = NULL; // do not deallocate
|
|
|
|
if ( NULL == service )
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
|
|
if ( S_OK == hr )
|
|
{
|
|
hr = service->GetEndpointReference( &wsdEpr );
|
|
|
|
if ( S_OK != hr )
|
|
{
|
|
PrintErrorMessage( L"Failed to obtain EPR", hr );
|
|
}
|
|
}
|
|
|
|
if ( !isByeMessage )
|
|
{
|
|
// If this is not a Bye message, we shall attempt to retrieve
|
|
// all fields that are available in the discovered service.
|
|
|
|
if ( S_OK == hr )
|
|
{
|
|
hr = service->GetProbeResolveTag( &probeResolveTag );
|
|
|
|
if ( S_OK != hr )
|
|
{
|
|
PrintErrorMessage( L"Failed to obtain tag", hr );
|
|
}
|
|
}
|
|
|
|
if ( S_OK == hr )
|
|
{
|
|
hr = service->GetInstanceId( &instanceId );
|
|
|
|
if ( S_OK != hr )
|
|
{
|
|
PrintErrorMessage( L"Failed to obtain Instance ID", hr );
|
|
}
|
|
}
|
|
|
|
if ( S_OK == hr )
|
|
{
|
|
hr = service->GetTypes( &typesList );
|
|
|
|
if ( S_OK != hr )
|
|
{
|
|
PrintErrorMessage( L"Failed to obtain types list", hr );
|
|
}
|
|
}
|
|
|
|
if ( S_OK == hr )
|
|
{
|
|
hr = service->GetScopes( &scopesList );
|
|
|
|
if ( S_OK != hr )
|
|
{
|
|
PrintErrorMessage( L"Failed to obtain scopes list", hr );
|
|
}
|
|
}
|
|
|
|
if ( S_OK == hr )
|
|
{
|
|
hr = service->GetXAddrs( &xAddrsList );
|
|
|
|
if ( S_OK != hr )
|
|
{
|
|
PrintErrorMessage( L"Failed to obtain XAddrs list", hr );
|
|
}
|
|
}
|
|
|
|
if ( S_OK == hr )
|
|
{
|
|
hr = service->GetMetadataVersion( &metadataVersion );
|
|
|
|
if ( S_OK != hr )
|
|
{
|
|
PrintErrorMessage( L"Failed to obtain metadata version", hr );
|
|
}
|
|
}
|
|
|
|
if ( S_OK == hr )
|
|
{
|
|
hr = service->GetLocalTransportAddress( &localAddress );
|
|
|
|
if ( S_OK != hr )
|
|
{
|
|
PrintErrorMessage( L"Failed to obtain local transport address", hr );
|
|
}
|
|
}
|
|
|
|
if ( S_OK == hr )
|
|
{
|
|
hr = service->GetRemoteTransportAddress( &remoteAddress );
|
|
|
|
if ( S_OK != hr )
|
|
{
|
|
PrintErrorMessage( L"Failed to obtain remote transport address", hr );
|
|
}
|
|
}
|
|
|
|
if ( S_OK == hr )
|
|
{
|
|
hr = service->GetLocalInterfaceGUID( &localGuid );
|
|
|
|
if ( S_OK != hr )
|
|
{
|
|
PrintErrorMessage( L"Failed to obtain Local Interface GUID", hr );
|
|
}
|
|
}
|
|
|
|
if ( S_OK == hr )
|
|
{
|
|
hr = service->GetExtendedDiscoXML(
|
|
&extendedXmlHeader, &extendedXmlBody );
|
|
|
|
if ( S_OK != hr )
|
|
{
|
|
PrintErrorMessage( L"Failed to extended discovery XML", hr );
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if ( S_OK == hr )
|
|
{
|
|
if ( isByeMessage )
|
|
{
|
|
// only print the EndpointReference if this is a Bye message
|
|
wprintf( L"EndpointReference: %s\r\n", wsdEpr->Address );
|
|
}
|
|
else
|
|
{
|
|
// print everything if this is not a Bye message
|
|
|
|
wprintf( L"Tag: %s\r\n", probeResolveTag );
|
|
|
|
wprintf( L"EndpointReference: %s\r\n", wsdEpr->Address );
|
|
|
|
wprintf( L"EndpointReference Properties:\r\n" );
|
|
|
|
if ( NULL == wsdEpr->ReferenceProperties.Any )
|
|
{
|
|
wprintf( L" No EndpointReference Properties\r\n" );
|
|
}
|
|
else
|
|
{
|
|
PrintXmlElement( wsdEpr->ReferenceProperties.Any, 1 );
|
|
}
|
|
|
|
wprintf( L"EndpointReference Parameters:\r\n" );
|
|
|
|
if ( NULL == wsdEpr->ReferenceParameters.Any )
|
|
{
|
|
wprintf( L" No EndpointReference Parameters\r\n" );
|
|
}
|
|
else
|
|
{
|
|
PrintXmlElement( wsdEpr->ReferenceParameters.Any, 1 );
|
|
}
|
|
|
|
wprintf( L"InstanceId: %llu\r\n", instanceId );
|
|
|
|
wprintf( L"Types:\r\n" );
|
|
PrintNameList( typesList );
|
|
|
|
wprintf( L"Scopes:\r\n" );
|
|
PrintUriList( scopesList );
|
|
|
|
wprintf( L"XAddrs:\r\n" );
|
|
PrintUriList(xAddrsList);
|
|
|
|
wprintf( L"Metadata Version: %llu\r\n", metadataVersion );
|
|
wprintf( L"Local Transport Address: %s\r\n", localAddress );
|
|
wprintf( L"Remote Transport Address: %s\r\n", remoteAddress );
|
|
|
|
wprintf( L"Local Interface GUID: " );
|
|
PrintGuid( localGuid );
|
|
wprintf( L"\r\n" );
|
|
|
|
wprintf( L"Extended XML Header:\r\n" );
|
|
PrintXmlElement( extendedXmlHeader, 1 );
|
|
|
|
wprintf( L"Extended XML Body:\r\n" );
|
|
PrintXmlElement( extendedXmlBody, 1 );
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
void PrintNameList
|
|
( _In_opt_ WSD_NAME_LIST *typesList
|
|
)
|
|
{
|
|
if ( NULL == typesList )
|
|
{
|
|
wprintf( L" None\r\n" );
|
|
}
|
|
else
|
|
{
|
|
while ( NULL != typesList )
|
|
{
|
|
wprintf( L" " );
|
|
|
|
if ( NULL == typesList->Element ||
|
|
NULL == typesList->Element->Space )
|
|
{
|
|
// Chances of this happening is rare, but we
|
|
// handle it anyway.
|
|
wprintf( L"ERROR: Type or namespace missing" );
|
|
}
|
|
else
|
|
{
|
|
// Since the URI of the namespace is too long, we have opted not to
|
|
// have it printed here. However, you may access that information
|
|
// through typesList->Element->Space->Uri.
|
|
wprintf( L"%s:%s", typesList->Element->Space->PreferredPrefix,
|
|
typesList->Element->LocalName );
|
|
}
|
|
|
|
wprintf( L"\r\n" );
|
|
|
|
typesList = typesList->Next;
|
|
}
|
|
}
|
|
}
|
|
|
|
void PrintUriList
|
|
( _In_opt_ WSD_URI_LIST *scopesList
|
|
)
|
|
{
|
|
if ( NULL == scopesList )
|
|
{
|
|
wprintf( L" None\r\n" );
|
|
}
|
|
else
|
|
{
|
|
while ( NULL != scopesList )
|
|
{
|
|
wprintf( L" %s\r\n", scopesList->Element );
|
|
scopesList = scopesList->Next;
|
|
}
|
|
}
|
|
}
|
|
|
|
void PrintXmlElement
|
|
( _In_opt_ WSDXML_ELEMENT *element
|
|
, UINT indentLevel
|
|
)
|
|
{
|
|
WSDXML_ATTRIBUTE *tempAttribute = NULL; // iteration - do not delete
|
|
|
|
PrintIndentTabs( indentLevel );
|
|
|
|
if ( NULL == element )
|
|
{
|
|
wprintf( L"No XML element\r\n" );
|
|
}
|
|
else
|
|
{
|
|
if ( NULL == element->Name ||
|
|
NULL == element->Name->Space )
|
|
{
|
|
// This is rare, but we still handle it.
|
|
wprintf( L"ERROR: Malformed name" );
|
|
}
|
|
else
|
|
{
|
|
wprintf( L"%s:%s",
|
|
element->Name->Space->PreferredPrefix,
|
|
element->Name->LocalName );
|
|
}
|
|
|
|
wprintf( L" " );
|
|
|
|
if ( NULL == element->FirstAttribute )
|
|
{
|
|
wprintf( L"[No Attributes]" );
|
|
}
|
|
else
|
|
{
|
|
tempAttribute = element->FirstAttribute;
|
|
|
|
while ( NULL != tempAttribute )
|
|
{
|
|
wprintf( L"[" );
|
|
|
|
if ( NULL == tempAttribute->Name || NULL == tempAttribute->Name->Space )
|
|
{
|
|
// it's odd for an attribute to exist without a name
|
|
// we will therefore ignore it
|
|
wprintf( L"ERROR: Malformed attribute" );
|
|
}
|
|
else
|
|
{
|
|
// Since the URI of the namespace is too long, we have opted not to
|
|
// have it printed here. However, you may access that information
|
|
// through typesList->Element->Space->Uri.
|
|
wprintf( L"%s:%s: %s", tempAttribute->Name->Space->PreferredPrefix,
|
|
tempAttribute->Name->LocalName, tempAttribute->Value );
|
|
}
|
|
|
|
wprintf( L"] " );
|
|
|
|
tempAttribute = tempAttribute->Next;
|
|
}
|
|
}
|
|
|
|
wprintf( L"\r\n" );
|
|
|
|
// We limit recursion level to 255 to avoid stack overflow problems
|
|
// which can be a security risk. In addition, we only print when a
|
|
// child is present.
|
|
if ( NULL != element->FirstChild && 255 > indentLevel )
|
|
{
|
|
PrintXmlNode( element->FirstChild, indentLevel + 1 );
|
|
}
|
|
}
|
|
|
|
tempAttribute = NULL;
|
|
}
|
|
|
|
void PrintXmlNode
|
|
( _In_opt_ WSDXML_NODE *node
|
|
, UINT indentLevel
|
|
)
|
|
{
|
|
PrintIndentTabs( indentLevel );
|
|
|
|
if ( NULL == node )
|
|
{
|
|
wprintf( L"No XML Node\r\n" );
|
|
}
|
|
else
|
|
{
|
|
while ( NULL != node )
|
|
{
|
|
if ( WSDXML_NODE::ElementType == node->Type )
|
|
{
|
|
// same indent level
|
|
PrintXmlElement( (WSDXML_ELEMENT*)node, indentLevel );
|
|
}
|
|
else // TextType
|
|
{
|
|
wprintf( L"%s\r\n", ((WSDXML_TEXT*)node)->Text );
|
|
}
|
|
|
|
node = node->Next;
|
|
}
|
|
}
|
|
}
|
|
|
|
void PrintIndentTabs
|
|
( _In_ UINT indentLevel
|
|
)
|
|
{
|
|
UINT i = 0;
|
|
|
|
for ( i = 0; i < indentLevel; i++ )
|
|
{
|
|
wprintf( L" " );
|
|
}
|
|
}
|