Sdílet prostřednictvím


Rozšíření tiskárny

Důležité

Moderní tisková platforma je upřednostňovaná pro komunikaci s tiskárnami ve Windows. Doporučujeme použít ovladač třídy doručené pošty IPP od Microsoftu spolu s tiskovými podpůrnými aplikacemi (PSA) k přizpůsobení prostředí tisku ve Windows 10 a 11 pro vývoj zařízení tiskárny.

Další informace najdete v průvodci návrhem aplikace podpory tisku v1 a v2.

Aplikace rozšíření tiskárny podporují předvolby tisku a oznámení tiskárny, když uživatelé spouštějí existující aplikace na ploše Windows.

Rozšíření tiskárny lze sestavit v libovolném jazyce podporujícím model COM, ale jsou optimalizovaná tak, aby byla sestavena pomocí rozhraní Microsoft .NET Framework 4. Rozšíření tiskárny mohou být distribuována s balíčkem ovladače tisku, pokud jsou podporující XCopy a nemají žádné závislosti na externích modulech runtime kromě těch, které jsou součástí operačního systému, například .NET. Pokud aplikace rozšíření tiskárny nesplňuje tato kritéria, může být distribuována do setup.exe nebo balíčku MSI a inzerována v prostředí Device Stage tiskárny pomocí direktivy PrinterExtensionUrl uvedené v manifestu v4. Pokud je aplikace rozšíření tiskárny distribuovaná prostřednictvím balíčku MSI, máte možnost přidat ovladač tisku do balíčku nebo ho nechat a distribuovat ovladač samostatně. Url rozšíření tiskárny se zobrazí v prostředí předvoleb tiskárny.

Správci IT mají několik možností pro správu distribuce rozšíření tiskárny. Pokud je aplikace zabalená v setup.exe nebo MSI, můžou správci IT používat standardní nástroje pro distribuci softwaru, jako je Microsoft Endpoint Configuration Manager, nebo můžou zahrnout aplikace do standardní image operačního systému. Správci IT můžou také přepsat soubor PrinterExtensionUrl zadaný v manifestu verze 4, pokud upraví HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers\<název> tiskové fronty\PrinterDriverData\PrinterExtensionUrl.

A pokud se podnik rozhodne blokovat rozšíření tiskárny úplně, můžete to provést pomocí zásad skupiny s názvem Konfigurace počítače\Šablony pro správu\Tiskárny\Nepovolit ovladače tiskárny v4 zobrazit aplikace rozšíření tiskárny".

Sestavení rozšíření tiskárny

Při vývoji rozšíření tiskárny je potřeba si uvědomit šest hlavních oblastí zaměření. Tyto oblasti fokusu se zobrazují v následujícím seznamu.

  • Registrace

  • Povolení událostí

  • Obslužná funkce OnDriverEvent

  • Předvolby tisku

  • Oznámení o tiskárně

  • Správa tiskáren

Registrace

Rozšíření tiskárny jsou registrována v tiskovém systému zadáním sady klíčů registru nebo zadáním informací o aplikaci v části PrinterExtensions souboru manifestu v4.

Existují zadané identifikátory GUID, které podporují každý z různých vstupních bodů pro rozšíření tiskárny. Tyto identifikátory GUID v souboru manifestu verze 4 nemusíte používat, ale musíte znát hodnoty GUID, abyste mohli použít formát registru pro instalaci ovladače v4. V následující tabulce jsou uvedeny hodnoty GUID pro dva vstupní body.

Vstupní bod GUID
Předvolby tisku {EC8F261F-267C-469F-B5D6-3933023C29CC}
Oznámení o tiskárně {23BB1328-63DE-4293-915B-A6A23D929ACB}

Rozšíření tiskárny, která jsou nainstalována mimo ovladač tiskárny, musí být registrována pomocí registru. To zajistí, že rozšíření tiskárny mohou být nainstalována bez ohledu na stav tiskového serveru nebo konfigurační modul v4 na klientském počítači.

Po spuštění služby PrintNotify zkontroluje klíče registru v cestě [OfflineRoot] a zpracuje všechny čekající registrace nebo odregistrování. Po dokončení všech čekajících registrací nebo zrušení registrace se klíče registru odstraní v reálném čase. Pokud k umístění klíčů registru používáte skript nebo iterativní proces, budete možná muset znovu vytvořit klíč \[PrinterExtensionID] při každém zadání klíče \[PrinterDriverId]. Nekompletní nebo poškozené klíče se neodstraní.

Tato registrace je nutná pouze při první instalaci. Následující příklad ukazuje správný formát klíče registru použitý k registraci rozšíření tiskárny.

Poznámka:

[OfflineRoot] se používá jako zkratka pro HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\OfflinePrinterExtensions.

[OfflineRoot]
    \[PrinterExtensionId] {GUID}
           AppPath=[PrinterExtensionAppPath] {String}
           \[PrinterDriverId] {GUID}
                  \[PrinterExtensionReasonGuid]
(default) = ["0"|"1"] {REG_SZ 0:Unregister, 1:Register}
                  \…
                  \[PrinterExtensionReasonGuidN]
           \[PrinterDriverId2]
                  \[PrinterExtensionReasonGuid2.1]
                  \…
                  \[PrinterExtensionReasonGuid2.Z]
           …
           \[PrinterDriverIdM]
    \[PrinterExtensionId2]
    …
    \[PrinterExtensionIdT]

Například následující sada klíčů zaregistruje rozšíření tiskárny s PrinterExtensionIDGuid jako PrinterExtensionID a plně kvalifikovanou cestou ke spustitelnému souboru „C:\Program Files\Fabrikam\pe.exe“ pro {PrinterDriverID1Guid} a {PrinterDriverID2Guid} jako PrinterDriverID, spolu s důvody pro předvolby tiskárny a oznámení tiskárny.

[OfflineRoot]
    \{PrinterExtensionIDGuid}
           AppPath="C:\Program Files\Fabrikam\pe.exe"
           \{PrinterDriverID1Guid}
                 \{EC8F261F-267C-469F-B5D6-3933023C29CC}
            (default) = "1"
                 \{23BB1328-63DE-4293-915B-A6A23D929ACB}
            (default) = "1"
           \{PrinterDriverID1Guid}
                 \{EC8F261F-267C-469F-B5D6-3933023C29CC}
            (default) = "1"
                 \{23BB1328-63DE-4293-915B-A6A23D929ACB}
            (default) = "1"

Chcete-li odinstalovat stejné rozšíření tiskárny, je třeba zadat následující sadu klíčů.

[OfflineRoot]
    \{PrinterExtensionIDGuid}
           AppPath="C:\Program Files\Fabrikam\pe.exe"
           \{PrinterDriverID1Guid}
                 \{EC8F261F-267C-469F-B5D6-3933023C29CC}
            (default) = "0"
                 \{23BB1328-63DE-4293-915B-A6A23D929ACB}
            (default) = "0"
           \{PrinterDriverID1Guid}
                 \{EC8F261F-267C-469F-B5D6-3933023C29CC}
            (default) = "0"
                 \{23BB1328-63DE-4293-915B-A6A23D929ACB}
            (default) = "0"

Vzhledem k tomu, že rozšíření tiskárny se můžou spouštět v kontextu spuštěného uživatelem i v kontextu spuštěného událostí, je užitečné určit kontext, ve kterém je vaše rozšíření tiskárny spuštěné. To může aplikaci umožnit, aby například nevypisovala stav ve všech frontách, pokud byla spuštěna pro oznámení nebo předvolby tisku. Společnost Microsoft doporučuje, aby rozšíření tiskárny nainstalovaná odděleně od ovladače (například s MSI nebo setup.exe) měla používat přepínače příkazového řádku buď v místní nabídce Start, nebo v položce AppPath, která byla vyplněna v registru během registrace. Vzhledem k tomu, že rozšíření tiskárny, nainstalovaná s ovladačem, jsou umístěna do DriverStore, nebudou spuštěna mimo nastavení tisku nebo události oznámení tiskárny. V tomto případě proto není zadávání přepínačů příkazového řádku podporováno.

Když se rozšíření tiskárny registruje pro aktuální PrinterDriverID, musí být PrinterDriverID zahrnuto v AppPath. Například pro aplikaci rozšíření tiskárny s názvem printerextension.exe a hodnotou PrinterDriverID {GUID} by [PrinterExtensionAppPath] vypadalo následovně jako v následujícím příkladu:

"C:\program files\fabrikam\printerextension.exe {GUID}"

Povolení událostí

Při běhu musí rozšíření tiskárny povolit aktivaci události pro aktuální PrinterDriverID. Jedná se o Hodnotu PrinterDriverID, která byla předána aplikaci prostřednictvím pole args[] a umožňuje tiskovému systému poskytnout odpovídající kontext události z důvodů, jako jsou předvolby tisku nebo oznámení tiskárny.

Aplikace by tedy měla vytvořit nový PrinterExtensionManager pro aktuální PrinterDriverID, zaregistrovat delegáta pro zpracování události OnDriverEvent a volat Metodu EnableEvents pomocí PrinterDriverID. Tento přístup ilustruje následující fragment kódu.

PrinterExtensionManager mgr = new PrinterExtensionManager();
mgr.OnDriverEvent += OnDriverEvent;
mgr.EnableEvents(new Guid(PrinterDriverID1));

Pokud aplikace nevolá enableEvents do 5 sekund, Windows vyprší časový limit a spustí standardní uživatelské rozhraní. Aby bylo možné tuto možnost zmírnit, měla by rozšíření tiskáren dodržovat nejnovější osvědčené postupy týkající se výkonu, včetně následujících:

  • Zpožďujte co nejvíce inicializace aplikace, dokud nevoláte EnableEvents. Potom určete prioritu odezvy uživatelského rozhraní pomocí asynchronních metod a neblokujte vlákno uživatelského rozhraní během inicializace.

  • Použití nástroje ngen k vygenerování nativní bitové kopie během instalace Další informace naleznete v tématu Generátor nativních imagí.

  • Pomocí nástrojů pro měření výkonu můžete najít problémy s výkonem při načítání. Další informace naleznete v tématu Nástroje pro analýzu výkonu systému Windows.

Obslužná funkce DriverEvent

Po registraci obslužné rutiny OnDriverEvent a povolení událostí, pokud bylo spuštěno rozšíření tiskárny pro zpracování předvoleb tisku nebo oznámení tiskárny, bude obslužná rutina vyvolána. V předchozím fragmentu kódu byla metoda s názvem OnDriverEvent zaregistrována jako obslužná rutina události. V následujícím fragmentu kódu je parametr PrinterExtensionEventArgs objekt, který umožňuje vytváření předvoleb tisku a oznámení tiskárny. PrinterExtensionEventArgs je obálka pro IPrinterExtensionEventArgs.

static void OnDriverEvent(object sender, PrinterExtensionEventArgs eventArgs)
{
    //
    // Display the print preferences window.
    //

    if (eventArgs.ReasonId.Equals(PrinterExtensionReason.PrintPreferences))
    {
        PrintPreferenceWindow printPreferenceWindow = new PrintPreferenceWindow();
        printPreferenceWindow.Initialize(eventArgs);

        //
        // Set the caller application's window as parent/owner of the newly created printing preferences window.
        //

        WindowInteropHelper wih = new WindowInteropHelper(printPreferenceWindow);
        wih.Owner = eventArgs.WindowParent;

        //
        // Display a modal/non-modal window based on the 'WindowModal' parameter.
        //

        if (eventArgs.WindowModal)
        {
            printPreferenceWindow.ShowDialog();
        }
        else
        {
            printPreferenceWindow.Show();
        }
    }

    //
    // Handle driver events.
    //

    else if (eventArgs.ReasonId.Equals(PrinterExtensionReason.DriverEvent))
    {
        // Handle driver events here.
    }
}

Aby se zabránilo špatné uživatelské zkušenosti spojené s pádem nebo pomalým rozšířením tiskárny, systém Windows používá časový limit, pokud se EnableEvents nezavolá v krátkém čase po spuštění aplikace. Pokud chcete povolit ladění, je tento časový limit zakázán, pokud je ladicí program připojený ke službě PrintNotify.

Ve většině případů se ale veškerý kód související s aplikací, který nás zajímá, spustí až během nebo po zpětném volání OnDriverEvent. Během vývoje může být také užitečné zobrazit MessageBox před spuštěním předvoleb tisku nebo oznámení tiskárny z callbacku OnDriverEvent. Jakmile se zobrazí MessageBox, vraťte se do sady Visual Studio, vyberte ladění> Připojit k procesu a zvolte název vašeho procesu. Nakonec se vraťte do složky MessageBox a vyberte OK, abyste mohli pokračovat. Tím zajistíte, že uvidíte výjimky a narazíte na všechny zarážky z tohoto bodu dál.

V budoucnu mohou být podporovány nové identifikátory důvodů. V důsledku toho musí rozšíření tiskárny explicitně zkontrolovat ReasonID a nesmí použít příkaz "else" pro detekci posledního známého ReasonID. Pokud je přijat neznámý ReasonID, aplikace by se měla elegantně ukončit.

Předvolby tisku jsou řízeny objektem PrintSchemaEventArgs.Ticket. Tento objekt zapouzdřuje dokumenty PrintTicket i PrintCapabilities, které popisují funkce a možnosti zařízení. I když je k dispozici i základní XML, objektový model usnadňuje práci s těmito formáty.

Uvnitř každého objektu IPrintSchemaTicket nebo IPrintSchemaCapabilities existují funkce (IPrintSchemaFeature) a možnosti (IPrintSchemaOption). Zatímco rozhraní používaná pro funkce a možnosti jsou stejná bez ohledu na původ, chování se mírně liší v důsledku podkladového XML. Například dokumenty PrintCapabilities určují mnoho možností na funkci, zatímco dokumenty PrintTicket určují pouze vybranou (nebo výchozí) možnost. Podobně dokumenty PrintCapabilities určují lokalizované zobrazované řetězce, zatímco dokumenty PrintTicket ne.

Další informace o datové vazbě ve WPF najdete v tématu Přehled datových vazeb.

Aby se maximalizoval výkon, společnost Microsoft doporučuje, aby volání getPrintCapabilities měla být provedena pouze v případě, že je nutné aktualizovat dokument PrintCapabilities.

Když uživatel vybírá možnosti pomocí ovládacích prvků ComboBox svázaných s daty, objekt PrintTicket se automaticky aktualizuje. Když uživatel konečně klikne na OK, zahájí se řetěz asynchronního ověřování a dokončení. Tento asynchronní vzor je hojně používán, aby dlouho běžící úlohy nezačínaly ve vláknech uživatelského rozhraní a nezpůsobovaly zablokování v uživatelském rozhraní nebo aplikaci, která tiskne. Následuje seznam kroků použitých ke zpracování změn PrintTicket po kliknutí na tlačítko OK.

  1. PrintSchemaTicket se ověřuje asynchronně pomocí metody IPrintSchemaTicket::ValidateAsync .

  2. Po dokončení asynchronního ověřování vyvolá modul CLR (Common Language Runtime) metodu PrintTicketValidateCompleted.

    1. Pokud bylo ověření úspěšné, metoda CommitPrintTicketAsync je volána, a metoda CommitPrintTicketAsync volá metodu IPrintSchemaTicket::CommitAsync. A když je aktualizace PrintTicket úspěšně dokončena, vyvolá se metoda PrintTicketCommitCompleted, která zavolá pomocnou metodu spouštějící PrinterExtensionEventArgs.Request.Complete metodu k označení, že tiskové předvolby jsou dokončeny, a pak zavře aplikaci.

    2. V opačném případě uživateli zobrazí uživatelské rozhraní pro zvládnutí situace omezení.

Pokud uživatel kliknul na tlačítko zrušit nebo zavřel okno předvoleb tisku přímo, rozšíření tiskárny zavolá IPrinterExtensionEventArgs.Request.Cancel s příslušnou hodnotou HRESULT a zprávou pro protokol chyb.

Pokud proces rozšíření tiskárny zavřel a nevolal metody Complete nebo Cancel, jak je popsáno v předchozích odstavcích, tiskový systém se automaticky vrátí do uživatelského rozhraní poskytnutého Microsoftem.

K načtení informací o stavu zařízení můžou rozšíření tiskárny použít Bidi k dotazování tiskového zařízení. Pokud například chcete zobrazit stav rukopisu nebo jiné druhy stavu zařízení, rozšíření tiskárny můžou použít metodu IPrinterExtensionEventArgs.PrinterQueue.SendBidiQuery k vydávání dotazů Bidi na zařízení. Získání nejnovějšího stavu Bidi je dvoustupňový proces zahrnující nastavení obslužné rutiny události pro událost OnBidiResponseReceived a volání Metody SendBidiQuery s platným dotazem Bidi. Následující fragment kódu ukazuje tento dvoustupňový proces.

PrinterQueue.OnBidiResponseReceived += new
EventHandler<PrinterQueueEventArgs>(OnBidiResponseReceived);
PrinterQueue.SendBidiQuery("\\Printer.consumables");

Při přijetí odpovědi Bidi se vyvolá následující obslužná rutina události. Tato obslužná rutina události má také simulovanou implementaci stavu rukopisu, která může být užitečná během vývoje v případě, že zařízení není k dispozici. Objekt PrinterQueueEventArgs zahrnuje HRESULT i odpověď Bidi XML. Další informace o odpovědích Bidi XML naleznete v tématu Bidi Request and Response Schemas.

private void OnBidiResponseReceived(object sender, PrinterQueueEventArgs e)
{
    if (e.StatusHResult != (int)HRESULT.S_OK)
    {
        MockInkStatus();
        return;
    }

    //
    // Display the ink levels from the data.
    //

    BidiHelperSource = new BidiHelper(e.Response);
    if (PropertyChanged != null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs("BidiHelperSource"));
    }
    InkStatusTitle = "Ink status (Live data)";
}

Oznámení o tiskárně

Oznámení tiskárny jsou vyvolána přesně stejným způsobem jako předvolby tisku. Pokud iPrinterExtensionEventArgs v obslužné rutině OnDriverEvent indikuje, že ID důvodu odpovídá identifikátoru GUID DriverEvents, můžeme vytvořit zkušenost pro zpracování této události.

Následující proměnné jsou nejužitečnější pro zajištění funkčního zážitku z oznámení tiskárny.

  • PrinterExtensionEventArgs.BidiNotification – To nese kód XML Bidi, který způsobil aktivaci události.

  • PrinterExtensionEventArgs.DetailedReasonId – Obsahuje identifikátor GUID události z XML souboru události ovladače.

Nejdůležitější atribut z IPrinterExtensionEventArgs objektu pro oznámení je BidiNotification vlastnost. To přenese kód XML Bidi, který způsobil aktivaci události. Další informace o odpovědích Bidi XML naleznete v tématu Bidi Request and Response Schemas.

Správa tiskáren

Aby bylo možné podporovat roli rozšíření tiskárny jako aplikace, která se dá použít jako centrum pro správu a údržbu tiskáren, je možné vytvořit výčet tiskových front, pro které je aktuální rozšíření tiskárny registrováno, a získat stav pro každou frontu. V projektu PrinterExtensionSample se to neukazuje, ale do metody Main App.xaml.cs lze přidat následující fragment kódu, který zaregistruje obslužnou rutinu události.

mgr.OnPrinterQueuesEnumerated += new EventHandler<PrinterQueuesEnumeratedEventArgs>(mgr_OnPrinterQueuesEnumerated);

Po vytvoření výčtu front se obslužná rutina události zavolá a může proběhnout operace stavu. Tato událost se pravidelně spouští během životnosti aplikace, aby se zajistilo, že seznam výčtových tiskových front je aktuální, i když uživatel od jejího otevření nainstaloval další fronty. V důsledku toho je důležité, aby obslužná rutina události při každém spuštění nevytvořila nové okno a to se zobrazí v následujícím fragmentu kódu.

static void mgr_OnPrinterQueuesEnumerated(object sender, PrinterQueuesEnumeratedEventArgs e)
{
    foreach (IPrinterExtensionContext pContext in e)
    {
        // show status
    }
}

Aby bylo možné provádět úlohy údržby pomocí rozšíření tiskárny, společnost Microsoft doporučuje, aby starší rozhraní WRITEPrinter API bylo použito podle následujícího pseudokódu.

OpenPrinter
    StartDocPrinter
        StartPagePrinter
          WritePrinter
        EndPagePrinter
    EndDocPrinter
ClosePrinter

Osvědčené postupy pro zvýšení výkonu rozšíření tiskárny

Aby bylo zajištěno co nejlepší uživatelské prostředí, měla by být rozšíření tiskáren navržena tak, aby se načítá co nejrychleji. Projekt Ukázka rozšíření tiskárny je aplikace .NET, což znamená, že je integrovaná do zprostředkujícího jazyka (IL), který se musí zkompilovat za běhu do příslušného formátu pro nativní architekturu procesoru. Během instalace společnost Microsoft doporučuje nainstalovat rozšíření tiskáren podle osvědčených postupů, aby se zajistilo, že byla aplikace zkompilována pro architekturu nativního systému. Další informace o osvědčených postupech kompilace a instalace kódu najdete v tématu Vylepšení výkonu spouštění pro desktopové aplikace.

Společnost Microsoft také doporučuje, aby rozšíření tiskárny odložila úlohy inicializace, jako je načítání prostředků, až po zavolání metody EnableEvents. Tím se minimalizuje pravděpodobnost, že aplikace volá EnableEvents před vypršením 5sekundového časového limitu pro rozšíření tiskárny.

Po volání OnDriverEvent by rozšíření tiskáren měla inicializovat své uživatelské rozhraní a kreslit co nejrychleji, a využít asynchronní metody tam, kde je to možné k zajištění odezvy. Rozšíření tiskárny by neměla mít žádnou závislost na síťových voláních nebo Bidi, aby bylo možné vytvořit počáteční stav okna pro předvolby tisku nebo oznámení tiskárny.

Vzhledem k tomu, že uživatel provádí volby pomocí uživatelského rozhraní na obrazovce, který ovlivňuje PrintTicket, by rozšíření tiskárny mělo použít IPrintSchemaTicket::ValidateAsync metodu, aby bylo možné co nejdříve ověřit změny. Nakonec by rozšíření tiskárny mělo použít metodu IPrintSchemaTicket::CommitAsync k potvrzení změn PrintTicket.

Rozšíření tiskárny vždy běží mimo proces, který je vyvolal. Při vývoji rozšíření tiskárny proto musíte mít na paměti chování okna:

Ukázka rozšíření tiskárny ukazuje, jak vytvořit uživatelské rozhraní, které je obecně spuštěno jako horní okno. V některých případech se ale uživatelské rozhraní nezobrazí v popředí, například v případě, že proces, který způsobil vyvolání uživatelského rozhraní, běží na jiné úrovni integrity nebo při kompilaci procesu pro jinou architekturu procesoru. V tomto případě by rozšíření tiskárny mělo zavolat funkci FlashWindowEx, aby požádalo uživatele o svolení, že může přijít do popředí tím, že bliká ikonou na hlavním panelu.

Schémata žádostí a odpovědí Bidi

Přehled datových vazeb

Zlepšení výkonu spouštění desktopových aplikací

Generátor nativních imagí

Rozhraní schématu tisku

Nástroje pro analýzu výkonu systému Windows