3.2 Example 2: Discovering and Utilizing a Print Queue in a Workgroup

This example demonstrates the use cases described in section 2.5.3.4 and section 2.5.3.7.1.

In this example, a computer in a workgroup locates a shared print queue on another computer in the workgroup and sends a print job to the shared print queue.

In this example, there is no dedicated print server, no domain has been established, and no directory system is available. The clients in the workgroup are distinguished by their roles, already established, as follows:

  • Print server: One client in the workgroup is established as a print server and has already announced the shared print queues that it hosts to all other print servers in the workgroup, if there are any, by using the CIFS Browser Protocol [MS-BRWS]. The printers are shared by using the Print System Remote Protocol [MS-RPRN].<20>

  • Print client: One client is distinguished as a print client in the workgroup when it is directed by the user to send a print job to a print server. This print client can behave in other roles, such as print server or print browser server, but for this example the client acts in the role of a print client only.

  • Print browser server: One client in the workgroup is established as the print browser server, which enumerates available print servers and print queues to print clients. The print browser server has already announced this role to all the clients in the workgroup by using the CIFS Browser Protocol. Print clients locate the print browser server by using the CIFS and RAP protocols through a NetServerEnum method call in which the Level field is set to 101 and the Flags field to SV_TYPE_PRINTQ_SERVER. In order to act in the role of the print browser server, the print client also plays the role of a print server with at least one available shared print queue.

Only one print server in the workgroup behaves as the active print browser server at any given time. Other print servers, if there are any, behave as backup print browser servers. One of them becomes the new active print browser server if the current active print browser server becomes unavailable. The print browser server and the backup print browser servers exchange information about shared print queues in the workgroup by calling the RpcAddPrinter method ([MS-RPRN] section 3.1.4.2.3) and using the PRINTER_INFO_* structures ().

Typically, the first workgroup client that takes on the role of a print server that shares a print queue also becomes the print browser server for the workgroup.

Prerequisites

This example has the following prerequisites:

  • The general requirements as listed in Assumptions and Preconditions, section 2.4, are met.

  • Participating clients are configured to be members of the same workgroup.

  • The \pipe\spoolss endpoint can be accessed anonymously.

  • All participating clients support the CIFS Browser Protocol.

  • One of the clients has at least one shared print queue, so that at least one client is of type SV_TYPE_PRINTQ_SERVER, which is a requirement for this example.

  • Either the print client or print server supports the Print System Remote Protocol but not the Print System Asynchronous Remote Protocol [MS-PAR].<21> This precondition was chosen to illustrate the use of Print System Remote Protocol.<22>

  • The print client is configured to not use Windows Update to obtain the printer driver. This precondition is presented to illustrate the printer driver download from the print server.

  • The printer driver is available from the print server's print$ share.

Initial System State

This example applies in the following initial system state.

  • The print client does not have the printer driver for the print queue.

  • The print client does not have the printer driver package for the printer driver in its local driver store. This state is presented to illustrate printer driver download from the print server.

Final System State

  • The print client obtains the list of available print servers and print queues.

  • The print client has downloaded a printer driver for the print queue.

Tasks

This example is divided into four tasks.

  • Locating a print queue in a workgroup

  • Establishing a connection and registering for notifications

  • Submitting a print job and receiving notifications

  • Unregistering for notifications

Task 1: Locating a print queue in a workgroup

The following diagram shows the first part of this example, in which a print client locates a print queue in a workgroup and establishes a connection to the print queue. The sequence is described in the steps that follow the diagram.

Print client locating a print queue in a workgroup

Figure 20: Print client locating a print queue in a workgroup

The message group that is labeled "Locating a print queue in a workgroup" shows how the client enumerates the printers in the workgroup ([MS-RPRN] section 3.1.4.2.1).

The following steps describe task 1 of this example.

  1. The print client calls the RpcEnumPrinters method on the print browser server by using the Print System Asynchronous Remote Protocol. It requests whatever level of printer information structure the client requires ([MS-RPRN] section 3.1.4.2.1).

  2. The server returns ERROR_INSUFFICIENT_BUFFER and sets the countBytesNeeded parameter to the size that is required to store the requested printer information structures for all shared print queues.

  3. The client allocates an amount of memory equal to countBytesNeeded. The client calls RpcEnumPrinters and passes the allocated memory as a parameter.

  4. The server stores a printer information structure for each shared print queue in the output buffer, stores the number of print information structures in the printersFound parameter, and returns ERROR_SUCCESS.

    If the number of shared print queues on the server has increased between the first and second call to RpcEnumPrinters, the server also returns ERROR_INSUFFICIENT_BUFFER from the second call. In that case, the server updates the countBytesNeeded parameter so that the client can reallocate the buffer and repeat the call to RpcEnumPrinters.

    Task 2: Establishing a connection and registering for notifications

    The following diagram shows the second part of this example, in which a print client establishes a connection to a print queue and registers for notifications.

Print client establishing a connection and registering for notifications

Figure 21: Print client establishing a connection and registering for notifications

Message group

Description

References

Connecting to a printer

The client obtains the print server handle and information about the specified printer.

[MS-RPRN]

section 3.1.4.2

Getting printer driver information

The client obtains information about the device driver for the specified printer.

[MS-RPRN]

section 3.1.4.4

Downloading a driver

The client downloads a printer driver by using the SMB protocol.

[MS-SMB] section 2.2 and [MS-FASOD] section 3.5

Getting printer data

The client obtains configuration data and form information for a print queue.

[MS-RPRN] sections 3.1.4.2 and 3.1.4.5

Registering for notifications

The client creates a remote change notification object that monitors changes to printer objects and sends notifications of those changes to the client by using the RpcRouterReplyPrinter method.

[MS-RPRN]

section 3.1.4.10

The following steps describe task 2 of this example:

It is common for clients to listen for notifications from more than one thread. Therefore, the following sequence of steps for registration for notifications can be observed on the network multiple times.

  1. The print client calls the RpcOpenPrinterEx method on the print server for the designated print queue.

  2. The print server returns a handle to the print queue and a success code.

  3. The print client calls the RpcGetPrinter (*) method on the print server for the print queue handle.

  4. The print server returns the PRINTER_INFO structure with details about the print queue and a success code.

  5. The print client calls the RpcGetPrinterDriver2 (*) method on the print server for the print queue handle.

  6. This step consists of the following two parts:

    1. The print server returns the requested DRIVER_INFO structure, which contains details about the print queue's printer driver, such as the driver's file name and version, and a success code.

    2. The print client downloads the printer driver files from the print$ share of the print server by using the SMB protocol family. The print client has no control over whether the SMB Version 1.0 or SMB Version 2.0 protocol is used.

  7. The print client creates a connection to the print queue by creating a local print queue proxy object.

  8. The print client calls the RpcEnumPrinterKey (*) method on the print server for the designated print queue handle.

  9. The print server returns ERROR_MORE_DATA and sets the buffer size that is required for the subkey.

  10. The client allocates a buffer with the size as returned by the server. The client calls RpcEnumPrinterKey by passing the buffer as a parameter.

  11. The print server returns the requested printer data subkey of the specified key and a success code.

  12. The print client calls the RpcEnumPrinterDataEx (*) method on the print server for the designated print queue handle.

  13. The print server returns ERROR_MORE_DATA and sets the buffer size that is required for enumerating all value names and data for the specified printer and key.

  14. The client allocates a buffer with the size as returned by the server. The client calls RpcEnumPrinterDataEx and passes the allocated memory as a parameter.

  15. The print server returns the requested printer data key/value pairs and a success code.

  16. The print client calls the RpcEnumForms (*) method on the print server for the designated print queue handle.

  17. The print server returns ERROR_INSUFFICIENT_BUFFER and sets the buffer size that is required for the forms that the printer supports.

  18. The client allocates a buffer with the size as returned by the server. The client calls RpcEnumForms and passes the allocated memory as a parameter.

  19. The print server returns the requested form data and a success code.

  20. The print client calls the RpcGetPrinterData (*) method on the print server for the designated print queue handle to obtain values of specific keys.

  21. The print server returns the requested data and a success code.

  22. The print client calls the print server's RpcGetPrinterDriverDirectory method.<23>

  23. The print server responds with the name of its printer driver directory and a success code.

  24. The print client mirrors the returned data on the local print queue proxy object.

  25. The print client calls the RpcRemoteFindFirstPrinterChangeNotificationEx method on the print server with a print queue handle to begin the process for registering to receive print status notifications.

  26. The print server calls the RpcReplyOpenPrinter method on the print client to establish a notification channel.

  27. The print client returns the RpcReplyOpenPrinter method call with a handle to the notification channel.

  28. The print server returns the RpcRemoteFindFirstPrinterChangeNotificationEx method call with a success code.<24>

    Task 3: Submitting a print job and receiving notifications

    The following diagram shows the print client submitting a print job to the print queue.

Print client submitting a print job to the print queue

Figure 22: Print client submitting a print job to the print queue

The message group labeled "Submitting a print job and receiving notifications" in the preceding figure shows how the client receives asynchronous notification of changes on a print queue and how it submits a print job ([MS-RPRN] sections 3.1.4.9.1, 3.1.4.9.2, 3.1.4.9.3, 3.1.4.9.4, and 3.1.4.9.7).

The following steps describe task 3 of this example:

Asynchronously, and until the print server has finished processing the print job, the print server calls the RpcRouterReplyPrinterEx method on the print client to notify the client of changes on the print queue, such as job processing progress, status changes, or other changes.

  1. The print client calls the RpcOpenPrinterEx method on the print server to open a handle to the print queue for submitting a print job, and the print server returns a success code.

  2. The print client calls the RpcStartDocPrinter method on the print server, and the print server returns a job ID and a success code.

  3. The print client calls the RpcStartPagePrinter method on the print server, and the print server responds with a success code.

  4. The print client repeatedly calls the RpcWritePrinter method on the print server by sending successive portions of the print job. The print server responds to each call with a success code. This step is repeated until all the print data has been sent.

  5. The print client calls the RpcEndPagePrinter method on the print server, and the print server responds with a success code.

  6. When all print data has been sent, the print client calls the RpcEndDocPrinter method on the print server, and the print server responds with a success code.

  7. The print client calls the RpcClosePrinter method on the print server, and the print server returns a success code. This step occurs only if the print client does not proceed to the next portion of this example.

    Task 4: Unregistering for notifications

    The following diagram shows the print client unregistering for notifications.

Print client unregistering for notifications

Figure 23: Print client unregistering for notifications

Message group

Description

References

Unregistering for notifications

The client unregisters for notification of changes on the print queue.

[MS-RPRN] (section 3.1.4.10.2)

Disconnecting from a print queue

The client closes its handle to the printer object.

[MS-RPRN] (section 3.1.4.2.9)

The following steps describe task 4 of this example:

It is common for clients to listen for notifications from more than one thread. Therefore, the sequence of steps for unregistration for notifications can be observed on the network multiple times.

  1. When a print client is no longer consuming notifications, for example, when the user closes the print queue dialog user interface, the print client calls the RpcFindClosePrinterChangeNotification method on the print server.

  2. The print server calls the RpcReplyClosePrinter method on the print client, and the print client returns a success code.

  3. The print server responds to the RpcFindClosePrinterChangeNotification method with a success code.

  4. The print client calls the RpcClosePrinter method on the print server by using the handle to the print queue that was specified during registration, and the print server returns a success code.