Common WWSAPI errors: A NULL WS_STRUCT_DESCRIPTION was specified.
When you use WsUtil to generate stub code and then work with the generated structures, you may get E_INVALIDARG when making the call to the service and, with WWSAPI tracing turned on, see the error message “A NULL WS_STRUCT_DESCRIPTION was specified.”.
WS_STRUCT_DESCRIPTION is one of the WWSAPI serialization structures and describes how a structure should be serialized into XML and deserialized from XML. When you use WsUtil to generate the stub code, lots of complex structures will be generated, including WS_STRUCT_DESCRIPTION. You’ll need to make sure that the structures are initialized properly. By default, if you use a structure that has either a base structure or derived structure(s), you should use a generated function to initialize it. For example, say the schema in the WSDL defines a type Location that has two derived types UserLocation and GeocodeLocation, WsUtil will generate the Location type like the following:
#if !defined(WS_CPLUSPLUS)
typedef struct Location
{
const struct _WS_STRUCT_DESCRIPTION* _type;
double Altitude;
double Latitude;
double Longitude;
} Location;
void WINAPI Location_Init(Location*);
struct UserLocation* WINAPI Location_AsUserLocation(Location*);
struct GeocodeLocation* WINAPI Location_AsGeocodeLocation(Location*);
#endif
Notice the function Location_Init after the structure. In order to properly initialize a Location structure, you need to call the Location_Init function like this:
Location location = {NULL, 0, latitude, longitude};
Location_Init(&location);
When you get the E_INVALIDARG with the error message I mentioned above, it’s because you forgot to call the *_Init function, which will set the WS_STRUCT_DESCRIPTION structure (the location._type field in this example). The Location_Init is generated like the following:
#if !defined(WS_CPLUSPLUS)
void WINAPI Location_Init(Location* _Location)
{
((Location*)_Location)->_type =
(WS_STRUCT_DESCRIPTION*)&dev_virtualearth_net_webservices_v1_common1_xsd.globalTypes.Location;
}
#endif
The *_Init functions (and the _type field) won’t be generated for types that don’t have base type or derived types. When you are consuming a service without knowing the details of the server type definitions, it’s always a good idea to open up the generated header file to see if *_Init functions are generated for the structures you use.
Please note that this is the default behavior. If you define a preprocessor WS_CPLUSPLUS, the requirement is different. I’ll discuss that in a later post.
For further reading on WsUtil’s support of XML schema, please go to https://msdn.microsoft.com/en-us/library/dd815313(VS.85).aspx.