Wednesday, 17 March 2010

Web Services on Devices : Developing a Print Client in Windows Vista

With WSDAPIs generated in previous post, we can now start developing a Print client.

How do I start developing a Print Client?
For the Print Client to communicate with a WSD Printer, first it has to discover the WSD Printers on the network. For knowing about discovering the Printers on the network and getting the UUID – universally unique identifier for the printer, refer to the sample Function Discovery program in the following path - "Folder where windows SDK is installed\Samples\NetDs\FunctionDiscovery".

Discovering the Printers on the network and getting the UUID :
  • Sample program defines CMyFDHelper class which is used to discover PnP devices on the network. This can be tweaked to discover WSD Printers on the network.
  • Call HRESULT CoInitializeEx (LPVOID pvReserved, DWORD dwCoInit) with pvReserved = NULL and dwCoInit = COINIT_MULTITHREADED from main(); (Ref - ).This function initializes the Component Object Model (COM) for use by the current thread. Applications are required to use CoInitializeEx before they make any other COM library calls except for memory allocation functions.
  • For the exact changes to be made in CMyFDHelper class to discover WSD devices, please wait for my next post on WS Discovery.
  • Call ::CoUninitialize();

  • Creating Service Proxy and sending messages to the server:(Refer to the File Service example in Windows SDK folder, mentioned earlier)
  • Create a UUID for client by calling UuidCreate() function. Convert the obtained UUID to string format.
  • Create a Service proxy by calling CreateCPrinterServiceTypeProxy(LPCWSTR pszDeviceAddress, LPCWSTR pszLocalAddress, CPrinterServiceTypeProxy** ppProxyOut, IWSDXMLContext** ppContextOut) [defined in PrinterServiceTypeProxy.cpp, LPCWSTR is wchar*] passing UUIDs of device/server and client in pszDeviceAddress and pszLocalAddress respectively.This function returns CPrinterServiceTypeProxy which will be used for calling methods on the server. Client calls CPrinterServiceTypeProxy methods(like CreatePrintJob, SendDocument etc), which have the same interface that of server and they send the commands to the server. Note: We need to create IWSDDeviceProxy before creating any IWSDServiceProxy(CPrinterServiceTypeProxy is of this type and a single device can host multiple services). Creation of device proxy before service proxy is handled at CreateCPrinterServiceTypeProxy. [More details on device and service proxies can be found from the following link - ]
  • Create a Event Sink class for Server events. Define a class named CPrinterServiceTypeEventNotify derived from IPrinterServiceTypeEventNotify. Implement the IPrinterServiceTypeEventNotify methods defined as virtual, in this class – PrinterElementsChangeEvent, JobStatusEvent, JobEndStateEvent. These are call back functions which will be invoked when the server sends respective events. We can update our structures holding printer, job info in these functions.
  • Functions defined above will be called if the client is subscribed to the events from server. Call the subscribe functions like SubscribeToJobStatusEvent, SubscribeToJobEndStateEvent on service proxy i.e CPrinterServiceTypeProxy object.(these functions are defined in PrinterServiceTypeProxy.cpp)
  • Call the server functions on CPrinterServiceTypeProxy object. For example, for CreatePrintJob you need to send filled CREATE_PRINT_JOB_REQUEST_TYPE structure and CREATE_PRINT_JOB_RESPONSE_TYPE* for response. Type definitions for the same can be found in PrinterServiceTypeTypes.h

  • Resolving the Build Errors in Visual Studio:
  • Set the project dependencies and build order – Right click on project. Select Project Dependencies. Make sure Client project depends on the project created for Print Schema. Also set the build order as Print Schema project, Client project in the same window opened.
  • You may get compilation error for not able to find header files like PrinterServiceTypeProxy.h. Then check whether you have included the files from project for PrinterServiceSchema. To include them, right click on Projects. Select Properties -> Configuration Properties -> C/C++ -> General -> Additional Include directories and type project directory for PrinterServiceSchema.
  • You may get linker error (unresolved external symbol) for UuidCreate(). If so, check whether you have included rpcrt4.lib. To include the same, right click on Project. Select Properties -> Configuration Properties -> Linker -> Command line -> Additional options. Type rpcrt4.lib.
  • If you get linker errors for wsdapi functions make sure you have included wsdapi.lib.
  • With the above steps, you are now ready with the basic Print Client which communicates with the WSD Printer.

    No comments:


    Related Posts with Thumbnails