Menu ▾ ▴

#285 Printer change notifications

8
pending
1
2026-10-06
2026-10-02
No

To monitor printer changes, classic OWL applications handled WM_WININICHANGE, which alerted applications to changes in the old "WIN.INI" system file. This message has long since been deprecated and superseded by WM_SETTINGCHANGE. However, the purpose of the latter is to notify applications "when the SystemParametersInfo function changes a system-wide setting or when policy settings have changed". Notably, the documentation says nothing about printers.

To more reliably monitor printer changes, modern Windows provides the Print Spooler API. By using FindFirstPrinterChangeNotification and accompanying functions, an application can ask for notifications when selected changes to a printer occur.

The catch is that this API is signal-based and uses synchronisation primitives to wait for notifications. To OWL old-timers used to message loops and event handling in response tables, this may feel awkward and unfamiliar. OWLNext has long had support for waiting on signals in the message loop (see TApplication::WaitOnObject and TApplication::ObjectSignaled introduced in [r18]), which makes usage of the signal-based printer notification API surprisingly painless. But it would be really, really nice if it simply seamlessly integrated with normal event handling.

With this in mind, I propose that a new message, OWL_WM_PRINTERNOTIFICATION, be introduced; wrapping the change information generated by the Print Spooler API behind the scenes and dispatching it to the application's main window.

See [discussion:b4bb3a639d] for motivation.

Related

Commit: [r18]
Discussion: b4bb3a639d
News: 2026/10/owlet-reliable-printer-change-notifications

Discussion

  • Vidar Hasfjord

    Vidar Hasfjord - 2026-10-03

    This feature has now been implemented in Owlet [r8924]. Revision [r8925] fixes a bug in the implementation.

    Design and usage

    TPrinterNotificationServer provides an RAII wrapper around the Windows Print Spooler printer-change notification API. It owns the printer handle and notification handle established by FindFirstPrinterChangeNotification, retrieves printer-change information using FindNextPrinterChangeNotification, and forwards notifications into the familiar OWLNext message dispatch framework.

    TApplication integrates the notification handle with its existing object-wait mechanism. No additional polling loop or worker thread is required. The printer notification handle simply becomes an object waited on by the application's existing message loop.

    An application enables printer notifications by overriding the new virtual member function TApplication::GetPrinterNotificationServer and returning a configured TPrinterNotificationServer.

    class TPrintingApp : public TApplication
    {
      TPrinterNotificationServer PrinterNotificationServer;
    
    public:
    
      // Creates the printer notification server.
      //
      TPrintingApp(const tstring& name)
        : TApplication{name},
        PrinterNotificationServer{PRINTER_CHANGE_PRINTER}
      {}
    
      // Retrieves the printer notification server.
      //
      auto GetPrinterNotificationServer() -> TPrinterNotificationServer* override
      { return &PrinterNotificationServer; }
    
    };
    

    During initialization, the returned server's notification handle is added to the application's existing wait set. When the handle is signaled, the normal signal handling calls TApplication::ObjectSignaled, which in turn calls TPrinterNotificationServer::GetNotification and then TPrinterNotificationServer::Forward to deliver the resulting TInfo to the application's main window as an OWL_WM_PRINTERNOTIFICATION message.

    The message participates in OWLNext's normal Windows message dispatch.

    class TMainWindow : public TFrameWindow
    {
      ...
    
      // Retrieves handler for the given message, if any.
      // See: https://sourceforge.net/p/owlnext/wiki/Response_tables_without_macros
      //
      auto GetHandlerFunction(const TEvent& event) -> TDispatchDelegate override // TEventHandler
      {
        using T = TMainWindow;
        return SearchEntries<T, TFrameWindow>(*this, event, {
          MakeMessageEntry<OWL_WM_PRINTERNOTIFICATION, &T::EvPrinterNotification>(),
          ...
        });
      }
    
    private:
    
      // Handles OWL_WM_PRINTERNOTIFICATION.
      //
      void EvPrinterNotification(const TPrinterNotificationServer::TInfo&)
      { ... }
    
    };
    

    Sequence diagram

     

    Related

    Commit: [r8924]
    Commit: [r8925]


    Last edit: Vidar Hasfjord 2026-10-05
  • Vidar Hasfjord

    Vidar Hasfjord - 2026-10-06
    • status: open --> pending
    • assigned_to: Ognyan Chernokozhev
    • Group: unspecified --> 8
     
  • Vidar Hasfjord

    Vidar Hasfjord - 2026-10-06

    @jogybl committed:

    NEW: Ported from Owlet: Printer change notifications [r8934].

    The svn::mergeinfo for the relevant revisions was recorded in [r8938], which also merges [r8937] (added CHECK).

    Now that you've committed, I've given you ownership of the ticket, and I've set 'milestone' to 8 and 'status' to 'pending' for review and release.

     

    Related

    Commit: [r8934]
    Commit: [r8937]
    Commit: [r8938]

Anonymous
Anonymous

Add attachments
Cancel