4.5 Receiving Notifications on Printing Events

To receive notifications concerning state changes of print servers, printers, and print jobs, a client ("TESTCLT") can perform the following steps, as shown in the figure in Notification of Print System Changes (section 1.3.3).

  1. Open a handle to a printer using RpcOpenPrinter (section

    • The client calls RpcOpenPrinter.

       RpcOpenPrinter( L"\\\\CORPSERV\\My Printer", &hPrinter, L"RAW", &devmodeContainer, PRINTER_ACCESS_USE );
    • The server allocates a printer handle, writes it to hPrinter, and returns 0 (success).

  2. Register for change notifications using RpcRemoteFindFirstPrinterChangeNotificationEx (section

    • The client allocates and initializes a RPC_V2_NOTIFY_OPTIONS notifyOptions structure as follows:

       WORD notifyFieldsJob[] = { 0x000A /*JOB_NOTIFY_FIELD_STATUS*/, 0x000D /*JOB_NOTIFY_FIELD_DOCUMENT*/ };
       RPC_V2_NOTIFY_OPTIONS_TYPE notifyTypes[1] = {{1 /*JOB_NOTIFY_TYPE*/, 0, 0, 0, 2, notifyFieldsJob }};
       RPC_V2_NOTIFY_OPTIONS notifyOptions = {0x00000002,0x00000000,1,notifyTypes};
    • The client calls RpcRemoteFindFirstPrinterChangeNotificationEx.

       RpcRemoteFindFirstPrinterChangeNotificationEx( hPrinter, 0x00000100 /* PRINTER_CHANGE_ADD_JOB */, 0, L"\\\\TESTCLT", 4711, &notifyOptions );  
       /* The number 4711 is a unique number used as a cookie to match the server's response. */
    • The server calls the client's RpcReplyOpenPrinter (section method to open a reverse channel, which is used to send change notifications to the client. The client has to return a remote procedure call (RPC) binding handle that identifies the reverse channel.

      • The server calls RpcReplyOpenPrinter.

       RpcReplyOpenPrinter( L"\\\\TESTCLT", &hPrinterNotify, 4711, 1, 0, NULL );
      • The client opens a notification context and associates it with the open printer handle hPrinter. In order to do so, client matches the dwPrinterRemote value (4711 in this example).

      • The client writes the notification context handle to hPrinterNotify and returns 0 (success) to the server.

      • The server returns 0 (success) from processing RpcRemoteFindFirstPrinterChangeNotificationEx.

    • As long as the client stays registered for notifications, the server calls the client's RpcRouterReplyPrinter (section or RpcRouterReplyPrinterEx (section method for each change of the requested type that occurs on the server.

      Whenever the monitored print queue changes on the server, the server filters the change according to the filter options specified by the client in the registration call and:

       RPC_V2_NOTIFY_INFO notifyInfo;  /* Note: Pseudo-code only, assumes sufficient memory has been allocated for aData[] array at end of structure */
       notifyInfo.Version = 2;
       notifyInfo.Flags = 0;
       notifyInfo.Count = 1;
       notifyInfo.aData[0].Type = 1;   /* JOB_NOTIFY_TYPE */
       notifyInfo.aData[0].Field = 0xD /* JOB_NOTIFY_FIELD_DOCUMENT */ notifyInfo.aData[0].String.pszString = L"My Test Print Job Name";
       notifyInfo.aData[0].Id = 12;    /* This print job has ID 12 */
       RPC_V2_UREPLY_PRINTER reply;
       Reply.pInfo = &notifyInfo;
      • The server calls the client's RpcRouterReplyPrinterEx.

       RpcRouterReplyPrinterEx( hPrinterNotify, 1, 0x00000100 /* PRINTER_CHANGE_ADD_JOB */, &result, 0, &reply );
      • The client reflects the change in its internal state.

      • The client writes processing flags to the variable result and returns 0 (success).

  3. Route the change notifications to applications or process it to reflect state changes.

    The client makes local calls to applications or processes to notify them of the state change.

  4. When state changes are no longer accepted, the client unregisters from notifications by calling RpcFindClosePrinterChangeNotification (section with the handle returned by the call to RpcOpenPrinter.

     RpcFindClosePrinterChangeNotification( hPrinter );
    • The server calls the client's RpcReplyClosePrinter (section with the handle previously obtained by RpcReplyOpenPrinter, notifying the client to close the binding handle for the reverse channel.

       RpcReplyClosePrinter( &hPrinterNotify );
    • The client cleans up the notification context, writes NULL to hPrinterNotify, and returns 0 (success).

    • The server returns 0 (success) from RpcFindClosePrinterChangeNotification.

  5. The client closes the handle to the printer or server object using RpcClosePrinter (section

     RpcClosePrinter( &hPrinter );

    The server frees the memory associated with the print queue handle, sets hPrinter to NULL, and returns 0 (success).