Bug 4111

Summary: Переделать систему печати
Product: WINE@Etersoft Reporter: Виталий Перов <vitperov>
Component: Печать ; Диалог печатиAssignee: Виталий Перов <vitperov>
Status: CLOSED FIXED QA Contact: Денис Баранов <baraka>
Severity: minor    
Priority: P4    
Version: 1.0.10   
Target Milestone: ---   
Hardware: PC   
OS: All   
Whiteboard:
Заявки RT: Связано с:
Дата напоминания:
Bug Depends on:    
Bug Blocks: 42, 443, 4063, 5618, 6009    

Description Виталий Перов 2009-07-13 19:27:53 MSD
Сейчас печать осуществляется вызовом
комманды lpr через pipe()
При использовании pipe необходимо
передавать все параметры коммандной
строки сразу. (Т.е на момент вызова PSDRV_StartDoc
количество копий должно быть известным)

Выяснилось, что некоторые программы (например Word) могут изменять количество копий в процессе формирования документа.

Единственный способ решения данной баги -
переписать систему печать так, чтобы
печать происходила во временный файл (или
область памяти), а комманда lpr вызывалась бы
только из PSDRV_EndDoc, когда количество копий
точно известно.
Comment 1 Виталий Перов 2010-09-02 17:41:08 MSD
система печати в wine pure изменилась.

Теперь Она основана на функции ScheduleJob, которая берёт требуемые настройки из реестра.

Интересно то, что печать идёт в любом случае в файл, а уже затем этот файл перенаправляется в нужное место (читается из HKCU/Software/Wine/Printing/Spooler)

В качестве хака можно добавить туда что-нибудь вроде ETERPRINT, и добавить в  ScheduleJob отдельный кейс для этого. Однако пока не понятно откуда брать необходимые параметры (количество копий, дуплекс, разбивка по копиям).

Можно также протестировать различные поддерживаемые режимы:
LPR:
CUPS:
возможно в каких-то из них заработает передача параметров дуплекса и collate внутри PostScript.
Comment 2 Виталий Перов 2010-09-03 16:36:20 MSD
Откатил патч реализующий нашу систему печати:

commit dad71e013ee670dc2d7518c4fde55e587d3c291c
Author: Vitaly Perov <vitperov@etersoft.ru>
Date:   Fri Feb 5 15:02:13 2010 +0300

    wineps.drv: fix collate & duplex (fix eterbug #4721, #2843, #3688)

Попробую разобраться с новой системой из pure.
Comment 3 Виталий Перов 2010-09-03 19:19:31 MSD
Дополнительно откатил в eterhack патч:

commit 716f8a679c5dfff618874c866092f9820d4685ed
Author: Vitaly Lipatov <lav@etersoft.ru>
Date:   Mon Jul 20 20:35:52 2009 +0400

    wineps.drv: fix warning

Comment 4 Виталий Перов 2010-09-06 17:17:51 MSD
Разобрался. функция ScheduleJob ищет в реестре по ключу HKCU/Software/Wine/Printing/Spooler значение portnamе. В нашем случае оно равно L"LPR:HpTest". Если такого значениея нет, то она проверяет не содержится ли в строке port LPR: или CUPS:.
LPR:HpTest берётся из каких-то настроек по умолчанию (без HpTest).
Comment 5 Виталий Перов 2010-09-06 17:31:21 MSD
LPR:HpTest - берётся из настроек принтера из реестра.
Попробовал изменить на CUPS:HpTest
Теперь печать идёт через cups, но collate не работает.
Comment 6 Виталий Перов 2010-09-06 17:44:32 MSD
Пробовал добавить Collate внутрь PostScript-файла - не помогло.

для печати через cups используется функция:
ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
третий и четвёртый параметры - количество опций и сами опции.
Возможно при добавлении туда collate=true разбивка по копиям заработает
Comment 7 Виталий Перов 2010-09-06 18:26:07 MSD
> Возможно при добавлении туда collate=true
> разбивка по копиям заработает
> 
Для этого есть специальная функция cupsAddOption.
Добавил collate=true - ничего не изменилось.

Comment 8 Виталий Перов 2010-09-07 16:04:52 MSD
Итоги:
* Разбивка по копиям внутри PostScript файла предусмотрена, но не работает.
* Функции печати CUPS не предусматривают параметра collate.

Остаётся только один выход: использовать предыдущий работающий способ (через lpr).
Comment 9 Виталий Перов 2010-09-07 16:54:28 MSD
функция ScheduleJob - как-раз и отправляет документ на печать. Если формирование необходимой строки команды сделать именно здесь, то возможно решится бага 4063. Т.к к моменту вызова ScheduleJob количество копий должно быть уже известным.

Только проблема в том, как передать необходимые параметры (количество копий, разбивка, дуплекс) в ScheduleJob.

Функция ScheduleJob принимает только хендл принтера и JobID, притом информацию о том куда и как ей печать она берёт из ветки реестра, соответствующей этому принтеру.
Comment 10 Виталий Перов 2010-09-07 17:30:21 MSD
Функция получает информацию о принтере с помощью структуры PRINTER_INFO_5W. Вместо этого можно запрашивать структуру PRINTER_INFO_2W, в которой кроме этого содержится LPDEVMODEW pDevMode; А там уже есть поля, содержащие требуемые параметры.
Comment 11 Виталий Перов 2010-09-07 18:30:34 MSD
Сделал пробную версию патча - не работает.
В упомянутой структуре всегда стоит 1 копия и отключена разбивка.
Comment 12 Виталий Перов 2010-09-08 15:48:53 MSD
Вполне логично. Структура pDevMode, полученная с помощью GetPrinterW не связана с каким-то конкретным заданием для печати.

С помощью функции GetJobW можно получить структуру JOB_INFO_2A. Там тоже есть pDevMode. Возможно в этом случае там будут необходимые нам данные.
Comment 13 Виталий Перов 2010-09-08 17:08:10 MSD
Написал патч. Проверил. Не работает.
В структуре JOB_INFO_2W заполнены только поля JobId и pDocument. Остальные все пустые.
Comment 14 Виталий Перов 2010-09-08 17:51:37 MSD
Структуру JOB_INFO_2W заполняет функция get_job_info. Для неё видим только hPrinter, из которого она извлекает нужную структуру, соответствующую указанному заданию на печать. А оттуда - необходимые параметры.

Структура называется job_t. По всей видимости она чисто вайновская (т.е её можно было бы дополнить).
В ней добавить указатель на DevMode.
Comment 15 Виталий Перов 2010-09-08 18:22:44 MSD
Для установки параметров есть специальная функция SetJobW, но в wine она также заполняет только некоторые поля.
Можно попытаться её доработать (дописать сохранение devMode в новое поле job_t)
Comment 16 Виталий Перов 2010-09-08 19:32:36 MSD
Дописал поддержку нового параметра в функции SetJobW и GetJobW

Функцию SetJobW нужно вызывать из PSDRV_EndPage (в этот момент уже точно известно количество копий)
Дописал добавление devMode из функции PSDRV_EndPage.


Ура! В ScheduleJob параметре Collate и Copies передаются.
Остаётся только дописать патч, проверить, и привести его к нормальному виду.

Часть патча, касающаяся SetJobW и GetJobW может быть отправлена в wineqh, но вряд ли им понравится изменение структуры job_t
Comment 17 Виталий Перов 2010-09-08 20:04:35 MSD
Также функция GetJobW не заполняет поле pPrinterName

fixme:winspool:ScheduleJob Destination string = 'L"|lpr -P'(null)' -T'no name' -# 20563 -o Collate=False -o sides=one-sided"'

Возникает следующая проблема:
Структуру заполняет функция:
get_job_info, которой в качестве параметре передаётся hPrinter.
далее она определяет уровень, и вызывает get_job_info_2 для заполнения структуры JOB_INFO_2W. Проблема в том, что в get_job_info_2 передаётся именно job, и название принтера из hPrinter ей не доступно.

- добавлять параметр hPrinter в get_job_info_2 - выглядит не хорошо - патч вряд ли примут
- добавлять новые параметры во внутреннюю структуру job_t - дублирование информации
Comment 18 Виталий Перов 2010-09-09 17:11:32 MSD
Реализовал первый вариант (добавил аргумент в функцию).

Оказалось, что в структуре opened_printer_t поля name и printername заполнены каким-то хламом:

ixme:winspool:ScheduleJob Destination string = 'L"|lpr -P'鎠ø⽥潢瑴敬⽳畢獧ⸯ楷敮㐭ㄱ⼱潤摳癥捩獥振⼺楷摮睯⽳祳瑳浥㈳猯潰汯倯䥒呎剅⽓〰〰⸲偓L' -T'01.txt' -# 20563 -o Collate=True -o sides=one-sided"'
Comment 19 Виталий Перов 2010-09-09 18:20:31 MSD
Переделал. Сделал через дополнительное поле во внутренней структуре.
Заполняю поле при вызове SetJobW.

Опять работает не так, как надо.
fixme:winspool:ScheduleJob Destination string = 'L"|lpr -P'߈èst' -T'01.txt' -# 5 -o Collate=True -o sides=one-sided"'

Видимо память "затирается". Вместо ссылки надо копировать.
Comment 20 Виталий Перов 2010-09-09 18:54:58 MSD
нашёл проблему:

При вызове SetJobA все поля полученной структуры перекодируются в юникод. После этого вызывается SetJobW, а после её вызова все поля затираются. Т.е хранить саму строку - задача SetJobW
Comment 21 Виталий Перов 2010-09-09 19:40:00 MSD
Думаю алгоритм должен быть следующим:
При обновлении информации затирать старую стоку и выделять память под новую.
При этом не забывать очищать память при удалении задания.
Comment 22 Виталий Перов 2010-09-13 16:21:19 MSD
Функция SetJobА не обрабатывает параметр pPrinterName.
В комментариях сказано, что pPrinterName игнорируется функцией (имеется ввиду виндовой).
Скорее всего он заполняется при вызове AddJobA и больше не меняется.
Comment 23 Виталий Перов 2010-09-13 16:33:42 MSD
Реализовал. Проверил. Работает.
Comment 24 Виталий Перов 2010-09-13 17:31:34 MSD
Сделал патч. Приложил в eterwine и eterhack
Comment 25 Виталий Перов 2010-09-13 17:32:12 MSD
Багу закрываю