Сейчас печать осуществляется вызовом комманды lpr через pipe() При использовании pipe необходимо передавать все параметры коммандной строки сразу. (Т.е на момент вызова PSDRV_StartDoc количество копий должно быть известным) Выяснилось, что некоторые программы (например Word) могут изменять количество копий в процессе формирования документа. Единственный способ решения данной баги - переписать систему печать так, чтобы печать происходила во временный файл (или область памяти), а комманда lpr вызывалась бы только из PSDRV_EndDoc, когда количество копий точно известно.
система печати в wine pure изменилась. Теперь Она основана на функции ScheduleJob, которая берёт требуемые настройки из реестра. Интересно то, что печать идёт в любом случае в файл, а уже затем этот файл перенаправляется в нужное место (читается из HKCU/Software/Wine/Printing/Spooler) В качестве хака можно добавить туда что-нибудь вроде ETERPRINT, и добавить в ScheduleJob отдельный кейс для этого. Однако пока не понятно откуда брать необходимые параметры (количество копий, дуплекс, разбивка по копиям). Можно также протестировать различные поддерживаемые режимы: LPR: CUPS: возможно в каких-то из них заработает передача параметров дуплекса и collate внутри PostScript.
Откатил патч реализующий нашу систему печати: 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.
Дополнительно откатил в eterhack патч: commit 716f8a679c5dfff618874c866092f9820d4685ed Author: Vitaly Lipatov <lav@etersoft.ru> Date: Mon Jul 20 20:35:52 2009 +0400 wineps.drv: fix warning
Разобрался. функция ScheduleJob ищет в реестре по ключу HKCU/Software/Wine/Printing/Spooler значение portnamе. В нашем случае оно равно L"LPR:HpTest". Если такого значениея нет, то она проверяет не содержится ли в строке port LPR: или CUPS:. LPR:HpTest берётся из каких-то настроек по умолчанию (без HpTest).
LPR:HpTest - берётся из настроек принтера из реестра. Попробовал изменить на CUPS:HpTest Теперь печать идёт через cups, но collate не работает.
Пробовал добавить Collate внутрь PostScript-файла - не помогло. для печати через cups используется функция: ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL); третий и четвёртый параметры - количество опций и сами опции. Возможно при добавлении туда collate=true разбивка по копиям заработает
> Возможно при добавлении туда collate=true > разбивка по копиям заработает > Для этого есть специальная функция cupsAddOption. Добавил collate=true - ничего не изменилось.
Итоги: * Разбивка по копиям внутри PostScript файла предусмотрена, но не работает. * Функции печати CUPS не предусматривают параметра collate. Остаётся только один выход: использовать предыдущий работающий способ (через lpr).
функция ScheduleJob - как-раз и отправляет документ на печать. Если формирование необходимой строки команды сделать именно здесь, то возможно решится бага 4063. Т.к к моменту вызова ScheduleJob количество копий должно быть уже известным. Только проблема в том, как передать необходимые параметры (количество копий, разбивка, дуплекс) в ScheduleJob. Функция ScheduleJob принимает только хендл принтера и JobID, притом информацию о том куда и как ей печать она берёт из ветки реестра, соответствующей этому принтеру.
Функция получает информацию о принтере с помощью структуры PRINTER_INFO_5W. Вместо этого можно запрашивать структуру PRINTER_INFO_2W, в которой кроме этого содержится LPDEVMODEW pDevMode; А там уже есть поля, содержащие требуемые параметры.
Сделал пробную версию патча - не работает. В упомянутой структуре всегда стоит 1 копия и отключена разбивка.
Вполне логично. Структура pDevMode, полученная с помощью GetPrinterW не связана с каким-то конкретным заданием для печати. С помощью функции GetJobW можно получить структуру JOB_INFO_2A. Там тоже есть pDevMode. Возможно в этом случае там будут необходимые нам данные.
Написал патч. Проверил. Не работает. В структуре JOB_INFO_2W заполнены только поля JobId и pDocument. Остальные все пустые.
Структуру JOB_INFO_2W заполняет функция get_job_info. Для неё видим только hPrinter, из которого она извлекает нужную структуру, соответствующую указанному заданию на печать. А оттуда - необходимые параметры. Структура называется job_t. По всей видимости она чисто вайновская (т.е её можно было бы дополнить). В ней добавить указатель на DevMode.
Для установки параметров есть специальная функция SetJobW, но в wine она также заполняет только некоторые поля. Можно попытаться её доработать (дописать сохранение devMode в новое поле job_t)
Дописал поддержку нового параметра в функции SetJobW и GetJobW Функцию SetJobW нужно вызывать из PSDRV_EndPage (в этот момент уже точно известно количество копий) Дописал добавление devMode из функции PSDRV_EndPage. Ура! В ScheduleJob параметре Collate и Copies передаются. Остаётся только дописать патч, проверить, и привести его к нормальному виду. Часть патча, касающаяся SetJobW и GetJobW может быть отправлена в wineqh, но вряд ли им понравится изменение структуры job_t
Также функция 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 - дублирование информации
Реализовал первый вариант (добавил аргумент в функцию). Оказалось, что в структуре 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"'
Переделал. Сделал через дополнительное поле во внутренней структуре. Заполняю поле при вызове SetJobW. Опять работает не так, как надо. fixme:winspool:ScheduleJob Destination string = 'L"|lpr -P'߈èst' -T'01.txt' -# 5 -o Collate=True -o sides=one-sided"' Видимо память "затирается". Вместо ссылки надо копировать.
нашёл проблему: При вызове SetJobA все поля полученной структуры перекодируются в юникод. После этого вызывается SetJobW, а после её вызова все поля затираются. Т.е хранить саму строку - задача SetJobW
Думаю алгоритм должен быть следующим: При обновлении информации затирать старую стоку и выделять память под новую. При этом не забывать очищать память при удалении задания.
Функция SetJobА не обрабатывает параметр pPrinterName. В комментариях сказано, что pPrinterName игнорируется функцией (имеется ввиду виндовой). Скорее всего он заполняется при вызове AddJobA и больше не меняется.
Реализовал. Проверил. Работает.
Сделал патч. Приложил в eterwine и eterhack
Багу закрываю