Welcome to MSDN Blogs Sign in | Join | Help
WSDAPI 101 Part 5: Putting it all together to generate WS traffic

This is the fifth article in the WSDAPI 101 series.  You'll learn the most by starting at the beginning, although it's not required to understand the content in this article.

Now that we know all about the pieces required in a device-oriented Web Services application, it's time to assemble all the pieces into a working application.  You can accomplish this with any number of commercial or free Web Services stacks, but the explanation today will focus on Windows' WSDAPI, since that's what I work on.

Step 1: Set up your environment
There are three things you'll need.

  • Visual Studio or another compiler.  This article will focus on VS2005 and VS2008.
  • The Windows SDK for the WSDAPI headers, libraries, and WsdCodeGen.  The Windows Server 2008 SDK is the most recent one released, and it will let you build 32-bit or 64-bit applications for Vista or Server 2008, both of which include WSDAPI.  You can use the new configuration tool to point your Visual Studio installation to the SDK.
  • A WSDL.  This one is a little tricky--you can either write one on your own, or you can find the WSDL for the application you're coding for.  We'll use the FileService sample WSDL included in the Windows SDK.

Step 2: Create a Visual Studio solution and projects
At this point, you should decide if you want to build a virtual device (and service), a client, or both.  The remainder of this guide assumes you'd like to build both--but if you're only interested in one, you can omit some steps to decrease your development time and decrease the total size of your code.

I typically build console applications (one each for the client and device), but nearly any C++ project is acceptable.

To use WSDAPI objects, simply #include <wsdapi.h> and link in wsdapi.lib, which contains some helper and factory functions.  WSDAPI.dll, which contains the bulk of the stack, will be loaded automatically at runtime.

Step 3: Generate some code
Use the WsdCodeGen tool (included in the SDK) to create the generated layer to customize the WSDAPI interfaces to your application.  We'll generate both client-side code and device-side code; the latter requires you to provide some information about the device's characteristics (below, in the second step).

  1. Generate a config file for WsdCodeGen.  In the same directory as FileService.wsdl, run "wsdcodegen.exe /generateconfig:all FileService.wsdl"
  2. Modify codegen.config to suit your application.  Look for a block of lines near the top of the config file that have values like, "### Sample Manufacturer ###"  Change these so your device will present a usable name.  Most of these fields are mandatory.
  3. Generate code.  Lastly, run "wsdcodegen.exe /generatecode codegen.config" to generate IDL, C++, and header files.

That's it!  All of the generated code is complete.  Add these files to your Visual Studio project.  You'll have to tweak the files somewhat to get them to compile (WsdCodeGen was originally intended for the build environment in the Windows Driver Kit).  This will be fixed in the future.

Step 4: Create a service
Steps 4 and 5 are only necessary if you want to build a virtual device and host a service.  If you're not interested, you can skip to step 6.

Open the IDL file and inspect the interfaces inside.  The base interface is the one you must implement--in the case of FileService.wsdl, it's called FileService, and it only inherits from IUnknown.  You must properly implement IUnknown in your service class, and must at least implement empty stubs for all service methods.

Step 5: Create a device host for your service
The service must live inside a container--in WSDAPI, this container is the IWSDDeviceHost.  Both the FileService and StockQuote samples demonstrate how to create and configure a host.  The important steps are:

  1. Create an XML context with WSDXMLCreateContext
  2. Register your XML names with this context by calling FileServiceRegisterNamespaces
  3. Create a device host with WSDCreateDeviceHost.  You'll need to choose an ID for your host--remember this for step 6.
  4. Set metadata by supplying two generated structures ("this model metadata" and "relationship metadata") and one hand-built structure ("this device metadata") to the SetMetadata method.
  5. Register the FileServicePortType with RegisterPortType
  6. Instantiate your service object and register it with RegisterService
  7. Start the host with ... Start!

Of course, always remember to Stop and Terminate the host when finished, and always remember to clean up variables and handle errors. 

It looks like a lot of work, but the pattern is the same for every host.  The device host emphasizes flexibility over simplicity, so simple applications like FileService are often a little more work than necessary, but these apps can grow easily with the extended support in the WSDAPI objects.

Step 6: Create a client
Thankfully, this is simpler than creating a device.

  1. Create a device proxy with WSDCreateDeviceProxy.  Specify the device ID you chose in the previous step.  Searching for devices available on the network is an advanced topic, and will be covered in another article.
  2. Get a service proxy by calling GetServiceProxyByType
  3. Create a FileServiceProxy and initialize it with the service proxy in the previous step
  4. Send messages (e.g., GetFileList)

Step 7: Compile and run
That's it!  Simply build the code, fire up the device, and then run the client program.

At first glance, this article looks pretty intimidating.  There are certainly a lot of steps--some of which are fairly involved.  But once you understand the pattern of generating code, building an app, and compiling it all together, authoring complex network applications that can communicate with actual devices becomes really straightforward.  Sure, it may be easier to write a simple socket program to do what the StockQuote or FileService samples demonstrate, but the pattern above can be applied to a WSDL of any complexity and the effort required is the same.  Letting Web Services handle the messaging allows you to focus on the logic above the messaging and, more importantly, the overall solution that the application presents.

I hope you've enjoyed WSDAPI 101.  I'll continue to touch on basic concepts for the lifetime of this journal, but I'm hoping that this guide has served to illustrate the architecture and steps behind Web Services applications written for devices.  If you've got questions that weren't answered here, please feel free to post a comment.

Posted: Monday, March 24, 2008 9:10 PM by dandris
Filed under:

Comments

Garysh said:

Hi Dan,

I am a driver/imageprocessing developer and new to Client Server technologies... may be my issue is quite silly.

Step 3: Task 3 -> Generate Code

I followed your instructions and had a problem in the above step. FileService.h file is not generated, it leads to build failure. Ofcourse I copied the file from FileService project. Is it done intentionally???

Thought of letting you aware...

Thanks and Regards,

Garysh

# April 6, 2008 3:31 PM

dandris said:

Hi Garysh-

Visual Studio instructs MIDL to generate "FileService_h.h" instead of "FileService.h".  To fix this problem:

* Right click "FileService.idl" in the Solution Explorer, open Properties

* Navigate to MIDL, Output

* Change the Configuration dropdown to "All Configurations"

* Change the "Header File" field from "$(InputName)_h.h" to "$(InputName).h"

--D

# April 10, 2008 8:16 PM

nitin_anand108 said:

Hi Dan,

I am working on development of WIA scanner driver.

I have generated the code for scan service. The communication using WSDAPI is successful.

I want to know how can I know the detail of the error, when some call through generated code fails.

ex. if CreateScanJob fails it is returning E_FAIL always from generated code. How can I know the error details like if device is busy etc.

I have checked with microsoft's inbox scan driver.

On error the trace is showing, a method GetOperationFault being called.

Can you provide information what exactly it is doing?

Thanks in advance,

Nitin.

# April 28, 2008 7:55 AM

dandris said:

Hi Nitin-

The best way to inspect failures occuring through WSDAPI is to check the return code from the failing method.  We currently have no way for you to extract detailed information from inside WSDAPI.

If the calls are failing inside generated code, you can manually debug those as if they were hand-written source.

Inspecting the wire traffic using a network sniffer (e.g., Netmon or Wireshark) will allow you to see if the device is responding to the initial request.

Best of luck

--D

# April 28, 2008 1:51 PM

Nitin said:

Hi Dan,

Thanks a lot for instant reply.

I am using the same way for debugging and tools.

As you have told, currently WSDAPI not supporting getting details of error.

I have checked the traces from MS inbox scan driver. If some generated code call fails, like EndRetrieveImage, it is calling some method GetOperationFault. The traces also show some information about the error.

I just wanted to know how is it able to give those information.

FYI I am including some traces.

=============================================

WIA: 2264.3324 1161141 0 0 [wiaservc.dll] wiasDebugTrace, WSDScDrv: IScanService::EndRetrieveImage failed (hr = 0x80004005), executing IScanService::GetOperationFault..

WIA: 2264.3324 1161141 0 0 [wiaservc.dll] wiasDebugTrace, WSDScDrv: CWSDDevice::GetOperationFault..

WIA: 2264.3324 1161141 0 0 [wiaservc.dll] wiasDebugTrace, WSDScDrv: Executing IScanService::GetOperationFault..

WIA: 2264.3324 1161141 0 0 [wiaservc.dll] wiasDebugTrace, WSDScDrv: IScanService::GetOperationFault returned fault code: Sender, subcode: ClientErrorNoImagesAvailable, reason: The server has no images available to aquire.

WIA: 2264.3324 1161141 0 0 [wiaservc.dll] wiasDebugTrace, WSDScDrv: IScanService::GetOperationFault indicates no data (WIA_ERROR_PAPER_EMPTY): ClientErrorNoImagesAvailable

WIA: 2264.3324 1161141 0 0 [wiaservc.dll] wiasDebugTrace, WSDScDrv: IScanService::EndRetrieveImage returned no data, hr = 0x80210003

==================================================

I wanted to know what GetOperationFault is doing.

How is it able to get those details of error ?

Thanks,

Nitin.

# April 30, 2008 12:12 AM

dandris said:

Nitin-

Those traces are generated by the non-WSDAPI scan driver code, not WSDAPI.

If you're going to use your own driver instead of the in-box MSFT scan driver, your driver is responsible for tracing those failures.  Your driver has access to the same WSDAPI error codes as the MSFT scan driver.

--D

# April 30, 2008 2:56 PM

Saurabh said:

hi Dan,

I am trying to build a scanner driver for a device.

I have the wsdl file of the service. I am successfully generating the codegen.config from the wsdl file but when i am trying to generate the proxy, stub and various other file it is showing the following error

"WsdCodeGen.exe : ERROR :  is not a valid URL"

Can you help me in this

Thanks,

Saurabh

# May 29, 2008 8:08 AM

Sush said:

Hi ,

I am trying to develop new webservices for winodws CE network device.

I didt get , which wizard i need to use to create new webservices for winodws CE device using WSDAPI.

How to create new WSDL files for new service .

REgards,

Sush

# October 19, 2008 1:01 AM

dandris said:

Hello Sush-

There is no wizard to create a service for WSDAPI.  The steps are fairly straightforward, and are explained in the documentation for our samples (http://msdn.microsoft.com/en-us/library/bb872383(VS.85).aspx).

The WSDL files are distributed by whoever writes them.  If you are using the WSD-Print or WSD-Scan WSDL (for example), you can find them on the Microsoft website.  If you are using a WSDL from another agency, you will have to download the WSDL from them.  You may write your own WSDL as well, but you will be the only implementer until you distribute the WSDL to other software developers.

--Dan

# October 21, 2008 9:44 AM

rama said:

Hi Dan.

When i test  fileservice sample on my device, get operation of client side is not working in device.

How can i debug that in my device.

Rama.

# November 19, 2008 12:58 PM

dandris said:

Hi Rama-

I don't follow--can you explain the setup and what exactly is failing?  Is the client failing to generate a message, or is it failing inside the device?

Thanks

--D

# November 20, 2008 3:06 PM

Raveesh said:

Hi Dan,

You have explained how the client can communicate with the device if we know its device id. Can you please let me know how can I search for devices available on the network and then communicate with them?

Thanks

Raveesh

# May 6, 2009 5:42 AM

dandris said:

Hi Raveesh-

Take a look at scenario 3 in this post: http://blogs.msdn.com/dandris/archive/2008/04/28/what-s-the-deal-with-wsdapi-s-ws-discovery-interfaces.aspx

The short version is that you will want to use Function Discovery to search for devices.  Function Discovery allows you to specify constraints to limit your query (e.g., "only search for printers").

--D

# May 8, 2009 11:56 AM

Raveesh said:

Thanks Dan.

I found a sample program on Function Discovery, in Windows SDK, in the following folder - <Windows SDK folder>\Samples\NetDs\FunctionDiscovery.

# May 12, 2009 9:01 AM

dandris said:

Hi Raveesh-

Yep, that's correct.  The PnP-X samples also show Function Discovery at work.

I believe both the Function Discovery and the PnP-X samples will be moving to another directory in the SDK in more recent versions.  If you cannot find them under the "NetDs" directory you may want to look elsewhere in the SDK.

--D

# May 12, 2009 11:36 AM
Leave a Comment

(required) 

(required) 

(optional)

(required) 

  
Enter Code Here: Required

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Page view tracker