Diit.cz - Novinky a informace o hardware, software a internetu

Ve Windows 10 zlobí LPT port

Veterán našich diskuzí „Nedělák“, který se tu už dlouho neobjevil, protože má zjevně víc práce než já, mě upozornil na zajímavý problém. Windows 10 verze 1511 obsahují chybu, která činí tisk na LPT port téměř nemožným.
blog
Epson LX-100

(Článek na konci doplněn) Před tím, než vytáhnete z rukávu „esa“ typu „který mamlas by v dnešní době tiskl na tiskárny připojené k LPT portu“, vás musím zarazit: nechte si to od cesty, neboť jsou to narážky naprosto scestné. Je naprosto legitimní tisknout i ve Windows 10 na tiskárnu připojenou k LPT portu. Windows 10 LPT port podporují, stejně jako tiskárny na tento port připojené, přičemž pro mnohé z nich lze ovladače nainstalovat i bez stahování z různých neznámých či méně známých zdrojů - prostě připojíte tiskárnu, ovladač najdete na Windows Update, nainstalujete a tisknete. Prosil bych ty, kteří mají neodolatelnou touhu všem sdělit, že tiskárny připojitelné k LPT portu do současnosti nepatří, aby se vůbec nepokoušeli účastnit diskuze pod článkem, neboť na jejich názory podle toho mého není cílová skupina čtenářů tohoto článku vůbec zvědavá. Účelem článku je o tomto problému nejen informovat, ale pokusit se též nastínit nějaké řešení do té doby, než to opraví Microsoft. Tedy jestli to vůbec opraví.

Mám totiž takový pocit (klidně to berte jako praštěnou konspirační teorii), že právě staré dobré tiskárny, z nichž se velká část dá připojit právě do LPT portu, leží výrobcům tiskáren v žaludku, a Microsoft jako by jim vyšel vstříc tím, že implementuje kurvítko softwarovou cestou. Dodnes se na internetu vedou debaty o tom, jestli je to chyba, nebo vlastnost. Oč jde? Inu, jednoduše o to, že tiskárna připojená přes LPT port, defaultně netiskne a systém hází chybu, že tiskárna je v chybovém stavu, nebo že prostě nedokázala požadovaný dokument vytisknout. Mimochodem důležitá věc: v předchozí verzi Windows 10 (původní build 10480) to fungovalo korektně, stejně jako v dřívějších Windows. Kde to přestalo fungovat, je loňská listopadová verze 1511, tedy build 10586.

Analýza problému

Oprášil jsem tedy starší železo, které je i v dnešní době s klidem použitelné: topící 65nm čtyřjádro Core 2 Extreme QX6800, 6 GB RAM (2×2 + 2×1 GB), trochu toho hard disku (z lenosti - nechtělo se mi trápit SSDčko), kus grafiky (Radeon HD 3870 - ano, fosilie, ale stačí a hlavně funguje), desku Intel s nezbytným LPT portem a samozřejmě LPT tiskárnu - již zmíněnou LX-100. Její ovladač se instaluje tak, že se tiskárna musí přidat ručně, ovladač je třeba vyhledat na Windows Update příslušným tlačítkem a po několika minutách, kdy systém seznam ovladačů stáhne, vybrat „Epson LX Series 1 (80)“. Na tento ovladač tiskárna regulérně tiskne. Tedy měla by. Bezprostředně po její instalaci to obvykle funguje (tiskárna např. na vyžádání korektně vytiskne zkušební stránku).

A pak nastane zajímavý kolotoč, který začíná tím, že po restartu PC tiskárna netiskne. Prohledáním internetu jsem zjistil, že stačí udělat nějakou změnu na LPT portu - nastavit, aby používal přerušení, nebo aby ho nepoužíval, zapnout či vypnout legacy PnP - anebo jednoduše port zakázat a znovu povolit. A tiskárna se v tu ránu roztiskne a funguje takto až do dalšího restartu. Důležitá poznámka: jakmile takto LPT port „poškádlíte“, začne se hned tisknout to, co má tiskárna ve frontě (pokud jste to z fronty nesmazali), tedy to, co se před tím nevytisklo.

Windows 10 Chyba Tiskarny Lpt 1

Vlastními pokusy jsem si potvrdil, že to nemá nic do činění s ovladačem tiskárny, tiskovou frontou (služba spooler neboli zařazování tisku) nebo tiskárnou jako takovou. Zádrhel je prostě v obsluze LPT portu systémem Windows a zaregistroval jsem kdesi informaci o tom, že stejný problém trápí tiskárny připojené na COM port (často nějaké malé pokladní tiskárny a podobný ne zrovna domácí hardware).

Zajímavé je, že když chci tisknout „takzvaně z DOSu“ - tedy v příkazovém řádku poslat nějaký soubor do LPT1 prostým copy (např. copy soubor.txt lpt1), tak tiskárna po spuštění počítače soubor skutečně přijme, nestane se tedy to, že by došlo k chybě, jako když chci tisknout „z Windows“. Problém však nastane právě v momentě, kdy chcete tisknout „z Windows“ - z Notepadu, Wordu nebo z čehokoli jiného (např. zkušební stránka). V tu chvíli se LPT port „rozbije“ a tiskárna pak už netiskne ani „z DOSu“ posíláním souborů na port LPT1 - systém zahlásí chybu, že soubor nebyl nalezen - a myslí tím právě LPT1. Pak stačí ve správci zařízení LPT port „restartovat“ (zakázat a povolit) a tisk se znovu rozjede a vše funguje perfektně až do restartu.

To mě vedlo k myšlence proces restartu LPT portu zautomatizovat a zajistit přes plánovač úloh, aby se port prostě vypnul a zapnul. Toto jsem zrealizoval pomocí nástroje devcon.exe, což je malý několikakilobajtový nástroj, který je standardně součástí obrovského několikasetmegového balíku dostupného u Microsoftu. Na hrdinství není čas, klidně si devcon stáhněte třeba z ulož.to.

Nemá smysl se moc rozepisovat o tom, jak se s devconem pracuje. Výsledek je totiž takový, že i když to nastavíte správně a LPT port se např. po přihlášení uživatele restartuje, stejně vám to nepomůže. Zjistil jsem, že k inicializaci problémového stavu LPT tiskárny nevede nějaký výchozí stav Windows, ale snaha něco poprvé vytisknout ve Windows. Právě proto ve mě klíčí podezření, že spíš než o chybu jde o softwarové kurvítko.

Jak se tedy chyba projevuje

Předpokládejme, že tiskárnu už máme nainstalovanou. (připojenou, nainstalované ovladače, vyzkoušenou, že tiskne). Může nastat nějaký takovýto scénář:

  1. Spustíme počítač, přihlásíme se.
  2. Zkusíme tisknout „z Windows“ => CHYBA.
  3. Restartujeme LPT port - chyba zmizí a tiskárna tiskne až do restartu PC.

Anebo:

  1. Spustíme počítač, přihlásíme se.
  2. Zkusíme preventivně restartovat LPT port.
  3. Zkusíme tisknout „z Windows“ => CHYBA.
  4. Restartujeme LPT port - chyba zmizí a tiskárna tiskne až do restartu PC.

Anebo:

  1. Spustíme počítač, přihlásíme se.
  2. Zkusíme tisknout „z DOSu“ (tedy poslat něco na LPT1) => tiskne.
  3. Zkusíme tisknout „z Windows“ => CHYBA.
  4. Zkusíme tisknout „z DOSu“ (tedy poslat něco na LPT1) => CHYBA (soubor neexistuje, míněno LPT1).
  5. Restartujeme LPT port - chyba zmizí a tiskárna tiskne až do restartu PC („z DOSu“ i „z Windows“).

Z uvedeného vyplývá, že oprava problému nelze zautomatizovat pouhým restartem LPT portu. Klíčí ve mě podezření, že je to záměr. Podařilo se mi nicméně vymyslet řešení, které problém obchází a je automatické. Má jednu nevýhodu a sami jistě uhodnete, jakou.

„Řešení“

Řešení, které jsem narychlo spíchl, je takové polovičaté, ale třeba to někomu bude stačit, případně to poslouží jako odrazový můstek, jak pokračovat dál. Jak už víme, pouhý restart LPT portu nestačí, musíme zkusit něco vytisknout. Ano, to je ta nevýhoda. Prostě musíme, na nic lepšího jsem nepřišel ;-). Nelze jen tak poslat „z Windows“ do tiskárny na LPT portu nějaký bezvýznamný příkaz, po němž tiskárna „nehne brvou“ (i když nevylučuji, že v případě některých tiskáren to půjde). A zkopírováním sady neškodných ESC sekvencí do LPT portu si nepomůžeme, protože chyba se projeví až při tisku „z Windows“.

To nejjednodušší, co mě napadlo, je prostě a jednoduše poslat do tiskárny prázdnou stránku. To je možná nejméně neškodná „sada ESC sekvencí“, kterou lze „ve Windows“ vymyslet. Jak to zautomatizovat? Snadno. Použijeme prázdný textový soubor a notepad (ano, mám na mysli Poznámkový blok, ale s dovolením si to budu zkracovat). Ten musíme ještě nastavit tak, aby stránka neobsahovala záhlaví a zápatí, a pak už stačí jen ten soubor vytisknout. Notepad totiž umožňuje poslat soubor do tiskárny z příkazové řádky. Normálně stačí použít parametr /P, ale protože je téměř jisté, že v systému budeme mít těch tiskáren víc, použijeme raději /PT a specifikujeme, na kterou tiskárnu prázdnou stránku pošleme.

Vytvoříme si tedy dávkový soubor čili „baťák“ (byť to bude s příponou .CMD, kterou mám raději) a uděláme v něm následující kroky:

  1. Nastavíme notepad tak, aby záhlaví a zápatí bylo prázdné.
  2. Vytvoříme prázdný textový soubor
  3. Řekneme notepadu, aby ho vytiskl na zvolenou tiskárnu
  4. Chvilku počkáme (tím nic nezkazíme, ale je možné, že to není potřeba)
  5. Restartujeme LPT port
  6. Vytvořený prázdný soubor zase smažeme.
  7. (Tento bod je volitelný a uděláme ho pouze v případě, že jsme velcí puntičkáři.) Uvedeme záhlaví a zápatí notepadu do výchozího stavu.

Takto vytvořený skriptík následně zavedeme do plánovače úloh a nastavíme, aby se spustil po spuštění počítače. Předpokladem ke správné funkci je pochopitelně zapnutá tiskárna. Pokud tiskárnu zapnete až dodatečně, budete poté muset skriptík spustit ručně.

V mém případě vypadá skriptík takto:

@echo off
set log=%~dp0log.txt
reg add HKU\.DEFAULT\Software\Microsoft\Notepad /v szHeader /d "" /f
reg add HKU\.DEFAULT\Software\Microsoft\Notepad /v szTrailer /d "" /f
echo.>"%~dp0empty.txt"
notepad /PT "%~dp0empty.txt" "LX-100"
timeout 1 >nul
echo *** %DATE% - %TIME% *** >>%LOG%
%~dp0devcon disable '*PNP0401 >>%LOG%
echo *** %DATE% - %TIME% *** >>%LOG%
%~dp0devcon enable '*PNP0401 >>%LOG%
del "%~dp0empty.txt"
echo ===================================================================== >>%LOG%
echo.>>%LOG%

Pro ty, kteří skriptování v příkazovém řádku Windows moc nevládnou, vysvětlím, co to vlastně dělá:

%~dp0 je dynamická proměnná, která obsahuje cestu k právě spuštěnému skriptu. Je použita proto, aby všechny soubory, které jsou vytvářeny, byly vytvářeny v téže složce, odkud je spouštěn skript. Je tedy v podstatě úplně jedno, odkud skript spustíte, bude si vždycky vytvářet soubory tam, kde právě je. Např. druhý řádek definuje log soubor jako proměnnou i s celou cestou, odkud je skript spouštěn.

Řádky začínající reg add v tomto případě nastavují v registru prázdné záhlaví a zápatí notepadu pro účet SYSTEM. Pod ním totiž budeme v plánovači úloh skript spouštět. Je to tak proto, že to je univerzální řešení, tento účet je ve všech systémech Windows (dobrá, od NT výš ;) a má patřičná práva pro spuštění devconu, který nám bude zakazovat a povolovat LPT port.

Příkaz echo.>"%~dp0empty.txt" jednoduše vyrobí prázdný textový soubor empty.txt (opět v téměže umístění, jako je samotný skript). echo . vypisuje prázdný řádek a znak > přesměrovává tento výpis do zvoleného souboru. "Uvozovky" jsou kolem proto, aby skript fungoval i v případě umístění do složky, kde by v názvu cesty mohla stát mezera.

Řádek notepad /PT "%~dp0empty.txt" "LX-100" spouští notepad, parametrem /PT říká, že se má tisknout soubor, který je uveden jako následující parametr na tiskárnu uvedenou jako další parametr. V mém případě "LX-100". Tady pozor na několik věcí: jde o to, jak máte tiskárnu nazvanou v systému. Je potřeba tam zadat celý název a do uvozovek. I ten soubor určený k vytištění musí být v uvozovkách, jinak to nechodí. Pokud se vaše tiskárna jmenuje HP LaserJet 1100A (v kanclu vedle), musíte tam napsat "HP LaserJet 1100A (v kanclu vedle)". Jméno vaší tiskárny najdete v ovládacím panelu Zařízení a tiskárny. Tiskárnu si můžete pojmenovat podle libosti buďto při instalaci, nebo i dodatečně změnou jejího nastavení. Jak si to rozumí s diakritikou, jsem netestoval, bude v takovém případě nejspíše potřeba dát pozor na to, aby byl skript uložen v patřičné kódové stránce (OEM 852 - s tou totiž pracuje příkazový řádek Windows). Potenciálním problémům se vyhnete, pokud tiskárnu pojmenujete tak, aby jméno neobsahovalo diakritiku ;-).

Příkaz timeout 1 >nul prostě a jednoduše jednu sekundu počká a nic přitom nevypisuje. Můžete si tam nastavit sekund, kolik bude potřeba, stejně tak můžete zkusit ten řádek úplně vyhodit, možná to bez něj taky bude fungovat. Timeout je součástí Windows, kdybyste to nevěděli ;-) (nemusíte ho nikde hledat nebo používat obskurní ping 127.0.0.1 -w 1000 -n 1 a podobně).

Příkazy echo *** %DATE% - %TIME% *** >>%LOG% a všechny koncovky >>%LOG% používat nemusíte (stejně jako druhý řádek definující log soubor), já je tam má pro kontrolu. Vypisují mi do souboru datum a čas a dělají mi přehled v tom, co se děje, zkrátka jsem jako uživatel linuxových serverů zvyklý si dělat logy neboli soubory se záznamy toho, co se stalo. Znaky >> způsobují, že se text do souboru přidává na jeho konec (kdybych napsal jen >, tak se mi ten soubor pokaždé přepíše a původní obsah se ztratí, což není žádoucí). V logu pak bude třeba něco takového:

*** 14.02.2016 -  1:03:35,15 *** 
ACPI\PNP0401\4&2DD69C83&0                                   : Disabled
1 device(s) disabled.
*** 14.02.2016 -  1:03:35,19 ***
ACPI\PNP0401\4&2DD69C83&0                                   : Enabled
1 device(s) are enabled.
=====================================================================

Příkazy %~dp0devcon disable '*PNP0401 a %~dp0devcon enable '*PNP0401 jsou samotné manipulace s LPT portem, přičemž je jasné, že disable port zakáže a enable ho zase povolí. Nástroj devcon.exe mám tedy umístěný ve stejné složce jako samotný skript (to je to již známé %~dp0). Klíčovým prvkem je však to '*PNP0401. Tahle formulka definuje právě ten LPT port a může se stát, že ve vašem případě sem bude potřeba napsat něco jiného. Záleží na tom, jak je na vaší desce LPT port realizován. Pokud je to stará dobrá klasika na rozhraní LPC (prostě tak, jak se LPT porty dělaly snad od doby, kdy bylo v PCčkách vynalezeno Plug'n'Play), bude to s největší pravděpodobností právě tak, jak to mám uvedeno ve skriptu. Pokud máte PCI kartu a na ní LPT port, nejspíš tam budete muset napsat něco jako "*VEN_135A&DEV_0181*" nebo něco na ten způsob (záleží na kartě a výrobci). Pozor: pokud použijete i znak &, nezapomeňte kolem dát i uvozovky, jinak si toho můžete povypínat víc, než je zdrávo :). Než správnou formuli zanesete do skriptu, zkoušejte si to nejdřív odladit spouštěním devconu s parametrem enable a identifikací zařízení, že pracujete skutečně s tím, čím chcete. Parametr enable je převážně neškodný a devcon přitom vypíše, které zařízení se pokusil zapnout (bez ohledu na to, zda už je, nebo není zapnuto; předpoklad je, že už zapnuté je, takže pokusem ho zapnout nic nezkazíte). Pokud vám vypíše víc než jedno zařízení, nebo žádné, víte, že jste to napsali špatně ;). Devcon samozřejmě spouštějte jako správce, jinak to nebude fungovat. Detail toho, jak se zařízení identifikuje, najdete ve správci zařízení na konkrétním zařízení na kartě Podrobnosti ve vlastnostech ID hardwaru, ID kompatibility nebo i Cesta instance zařízení. Doporučuji nastudovat, jak se s devconem pracuje.

Finta skriptu pak spočívá v tom, že nejprve do tiskárny prázdný dokument pošle, v ten moment dojde někde potajmu (při spuštění plánovačem úloh) k tomu, že se dokument nevytiskne a systém vygeneruje chybu, kterou ale neuvidíte (protože skript bude spuštěn pod účtem SYSTEM). Dokument však zůstane ve frontě a vytiskne se sám poté, co devcon opět povolí LPT port.

del "%~dp0empty.txt" následně prázdný dokument smaže, čili po sobě uklidí. Dalo by se ještě uklidit i v registru to záhlaví notepadu pro účet SYSTEM (to je ten zmíněný volitelný 7. bod), ale to už jsem opravdu nepovažoval za nutné (za normálních okolností totiž účet SYSTEM nemá důvod tisknout z notepadu ;-).

Planovac Uloh

Skript pak následně zanesete do plánovače úloh, nastavíte, aby se spouštěl při spuštění PC, a to pod účtem SYSTEM. Hotovo.

Bezpečnostní riziko?

Samozřejmě, že existuje. Existuje vždy, když spouštíte něco jako SYSTEM. Ten má totiž podstatně víc pravomocí než Administrator, který už je v systémech Windows pár verzí nazpět standardně vypnutý (ale asi pořád méně než root v linuxu ;). Takže by nebyl problém na tohle řešení napasovat ovládnutí systému neadministrátorem - stačí zjistit, že toto řešení v systému existuje (např. pohledem do plánovače úloh) a skript zmodifikovat, aby dělal něco jiného. Neuškodí tedy, pokud skript někam schováte a nastavíte práva jen pro účet SYSTEM, aby ho nikdo jiný nemohl upravit. Ne, že by to nešlo, ale zase tím případnému útočníkovi hodíte nějaké to stéblo pod chůdy ;-). Rozhodně by měl mít problém takový soubor upravit uživatel s neadministrátorským oprávněním. Samozřejmě když bude uživatel přítomný u PC chtít toto ovládnout, udělá to jinak, ale to už není náš problém ;-).

Jak vlastně zareaguje tiskárna?

Jak která. Moje Epson LX-100 jen pohne hlavou tam a zpět a trošku otočí válcem, ale nevytiskne nic, ani si nepodá list papíru, takže v jejím případě jde o řešení vysoce efektivní a bez nutnosti „recyklovat“ v zásobníku prázdné listy papírů (pokud je však papír již zaveden, tak skutečně odstránkuje, tedy papír vyjede ven, což by mohl být problém v případě použití traktorového podavače, který jsem ale nezkoušel).

Ostatní tiskárny nemám vyzkoušené, takže jen hádám: laserovky buďto ohřejí prázdný list papíru, nebo se v lepším případě nestane vůbec nic, jen dojde k onomu požadovanému obejití problému. Inkoustovky v zásadě to samé, ale tam bych skutečně čekal projetí jednoho listu papíru. Co budou dělat malé pokladní tiskárny, to je otázka. Buďto z nich vyjede kus papíru (a možná se u některých modelů i ustřihne), nebo se také nestane nic, ale rozhodně nepředpokládám, že by tiskárna povila celou roličku. Záleží zkrátka na tom, jak si tiskárna přebere snahu vytisknout prázdnou stránku.

A teď smutná zpráva: celé toto řešení má kromě své krkolomnosti ještě jednu vadu na kráse: jakmile z nějakého důvodu restartujete službu zařazování tisku (print spooler), celý problém se opakuje od začátku. V ten moment by bylo samozřejmě zapotřebí znovu zkusit něco vytisknout a restartovat LPT port, to už by se nejspíš muselo udělat ručně (nenašel jsem způsob, jak zajistit, aby se po startu služby print spooler ještě automaticky spustil nějaký skript, ale třeba to jde, o řešení se můžete podělit v diskuzi).

A poslední drobnost: problém lze v případě tiskáren pro LPT port efektivně obejít pořízením něčeho, jako je print server s paralelním portem (já používám třeba staré dobré HP JetDirecty; existují i pront servery pro tiskárny na sériový port, ale jsou vzácnější a asi budou i dražší). Na tiskárnu tak budete tisknout síťově, takže s paralelním portem jako takovým ze softwarového hlediska nepřijdete do styku. Asi bych to preventivně neřešil „redukcí“ z USB na LPT - hodně by totiž záleželo na tom, zda jde o redukci, která na USB navěsí další (v podstatě virtuální) LPT port (pak by se problém nemusel vyřešit, protože LPT port je znovu ve hře), anebo jde o redukci, která LPT port zamaskuje a udělá z tiskárny de facto USB tiskárnu. Touto cestou by mohl být problém efektivně obejit. Opět to ale neřeší tiskárny na COM portu.

Nezbývá doufat, že to Microsoft do vydání nové verze Windows 10 opraví. Insideři si na to stěžují poměrně hodně, tak uvidíme. Jestli to opraveno nebude, pak to osobně definitivně považuji za záměr a tedy softwarové kurvítko.


Aktualizováno 28. 2. 2016: Vypadá to, že problém byl vyřešen počínaje Insider Preview Buildem 14271 z 24. (18.) 2. 2016. Lehce jsem ho zkoušel a tiskárna i bez zmíněné obezličky po startu PC (či restartu spooleru) normálně tiskne. Nezbývá než doufat, že ta oprava probublá až do finální aktualizace.

WIFT (Google+)

Bývalý dlouholetý redaktor internetového magazínu CDR-Server / Deep in IT, který se věnuje psaní článků o IT a souvisejících věcech prakticky od založení CD-R serveru.

více článků, blogů a informací o autorovi

Diskuse k blogu Ve Windows 10 zlobí LPT port

Středa, 2 Březen 2016 - 09:02 | Miroslav Krob | Mně zase zamrzelo, že ve Win10 nefunguje teaming...
Pondělí, 29 Únor 2016 - 13:40 | VITACZ | Co se týče ovladačů a updatů u W10 tak bych také...
Neděle, 28 Únor 2016 - 00:16 | WIFT | Ano, obšlehl jsem tu část, kde se říká, že se na...
Středa, 24 Únor 2016 - 13:04 | Jan Píša | Tak pro zajímavost - nalezení řešení na internetu...
Středa, 24 Únor 2016 - 12:09 | John Doe | Mi jich máme 105000, ale naštěstí bez používaného...
Středa, 24 Únor 2016 - 10:41 | Jan Píša | Můžete mi prosím sdělit to oficiální řešení,...
Středa, 24 Únor 2016 - 07:22 | wertty | **PNP0401 je v Windows Device Console (Devcon....
Středa, 24 Únor 2016 - 07:11 | Living Legend | Jo a kterej z postup k nápravě chyby je oficiální...
Středa, 24 Únor 2016 - 00:22 | John Doe | Protože nevím co je to hodnota **PNP0401, a s...
Středa, 24 Únor 2016 - 00:16 | John Doe | Jan Píša, ke vší úctě. Postujete neoficiální...

Zobrazit diskusi