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.