Russian Qt Forum

Qt => Печать => Тема начата: kosproger от Июль 04, 2012, 22:04



Название: Не создается объект QPrinter в отдельном процессе.
Отправлено: kosproger от Июль 04, 2012, 22:04
Доброго времени суток!
Есть один проект, состоящий из консольного и GUI приложения. Консоль собирает pdf-файлы по фтп и отправляет их на печать. GUI запускает данное консольное приложение, используя QProcess. Возникла такая проблема на машине заказчика: при запуске консольного приложения из GUI после того, как скачивается файл, процесс "останавливается" во время создания объекта QPrinter. Т.е. не выполняется строчка
Код:
QPrinter *printer = new QPrinter(QPrinter::HighResolution);
Но, при удалении данного запущенного процесса в GUI-приложении, алгоритм продолжает выполнятся. Т.е. создается объект printer и производится печать.
Если запустить консоль отдельно - все работает.
Плюс ко всему, такой проблемы у себя не наблюдаю...

Подскажите, пожалуйста, в чем может быть дело.


Название: Re: Не создается объект QPrinter в отдельном процессе.
Отправлено: kosproger от Июль 05, 2012, 14:16
Ситуация повторилась на других машинах, хотя у меня все в порядке и под Linux, и под Windows... Qt 4.8.1
Есть мысли?


Название: Re: Не создается объект QPrinter в отдельном процессе.
Отправлено: Bepec от Июль 05, 2012, 14:18
Телепаты в отпуске.


Название: Re: Не создается объект QPrinter в отдельном процессе.
Отправлено: kosproger от Июль 05, 2012, 14:45
GUI приложения позвоялет запускать/останавливать коносльное приложения через QProcess
запуск процесса:
Код:
QProcess *process = new QProcess();
process->setProcessChannelMode(QProcess::MergedChannels);
connect(process,SIGNAL(finished(int,QProcess::ExitStatus)),this,SLOT(onProcessFinished(int,QProcess::ExitStatus)));
connect(process,SIGNAL(readyReadStandardOutput()),this,SLOT(onRead()));
process->start(appDir + "/PDFPrinter", QStringList() << defProfile);
runnedProcesses.insert(defProfile,process);

Процесс запускается, работает. НО, после скачивания файла его работа останавливается (в прямом смысле) на создании объекта (строка, приведенная в первом посте). Т.е., допустим, если сделать так:
Цитировать
qDebug("before print\n");
QPrinter *printer = new QPrinter(QPrinter::HighResolution);
qDebug("after print\n");
получаю сообщения before print и все.

Если же завершить работу GUI, либо остановить работу консоли через GUI, продолжает выполняться его работа с выделенной строчки. Т.е. Создается printer, получаю сообщение after print, успешно печатается документ и завершается работа.

запущенные процессы храню в Qmap. Когда процесс надо завершить, ему отправляется сообщения об остановке и удаление процесса из Qmap. Получается, что, когда в GUI-приложении процесс удален, т.е. Отвязывается от него, создается printer.

Если запустить консольное приложения без основного все работает верно.
Что еще сообщить?


Название: Re: Не создается объект QPrinter в отдельном процессе.
Отправлено: kosproger от Июль 09, 2012, 10:45
ребят, ну я в отчаянии уже... может хоть какие мысли по этому поводу?
Если инфа неполная, что еще сообщить? Могу, в принципе, оба проекта приложить, но они не такие маленькие...


Название: Re: Не создается объект QPrinter в отдельном процессе.
Отправлено: Igors от Июль 09, 2012, 10:57
ребят, ну я в отчаянии уже... может хоть какие мысли по этому поводу?
Судя по Вашим словам порожденный процесс не может получить доступ к устройству. Мысли простые - надо смотреть в отладчике где висит, а там углубляться в исходники.


Название: Re: Не создается объект QPrinter в отдельном процессе.
Отправлено: kosproger от Июль 09, 2012, 11:09
Отладчиком надо смотреть что происходит в порожденном процессе. Но как это сделать?
Цитировать
рожденный процесс не может получить доступ к устройству
но я же не устаналиваю название принтера. Я просто создаю объект...


Название: Re: Не создается объект QPrinter в отдельном процессе.
Отправлено: Igors от Июль 09, 2012, 11:45
Отладчиком надо смотреть что происходит в порожденном процессе. Но как это сделать?
Запустить отладку порожденного, назначив родительский как стартовый. В тех IDE что работаю (Xcode и MSVC) это везде есть


Название: Re: Не создается объект QPrinter в отдельном процессе.
Отправлено: kosproger от Июль 09, 2012, 17:24
Вроде бы нашел, как в Qt Creator также сделать. Не знал, что возможно, спасибо за наводку!! :)
Осталось добраться до машины заказчика. Как будут результаты - сообщу.


Название: Re: Не создается объект QPrinter в отдельном процессе.
Отправлено: kosproger от Июль 18, 2012, 19:48
Наконец-то получилось добраться до машины заказчика. Понял почему работает у него и не работает у меня. У меня физического принтера нет, есть только виртуальный (PDFCreator). Заказчик работает с реальным принтером. Соответственно, если поставить драйвер на принтер, та же проблема появляется и у меня.
Если смотреть по Debug'у, то на строчке
Код:
QPrinter *printer = new QPrinter(QPrinter::HighResolution);
производится подключение одного из dll драйвера (hpzpi5mc.dll), затем начинается ожидание загрузки других dll. Если завершить GUI процесс, они подключаются, и продолжается работа. Мысли такие, что библиотеки эти блокируются как-то GUI-процессом, при его завершении, соответственно, освобождаются.


Название: Re: Не создается объект QPrinter в отдельном процессе.
Отправлено: kosproger от Июль 19, 2012, 13:45
Нет идей?


Название: Re: Не создается объект QPrinter в отдельном процессе.
Отправлено: Bepec от Июль 19, 2012, 14:07
Идеи от слов не появляются. Тут смотреть надо.


Название: Re: Не создается объект QPrinter в отдельном процессе.
Отправлено: Igors от Июль 19, 2012, 14:10
Нет идей?
Ну надо найти на каком системном вызове виснет - и читать про него


Название: Re: Не создается объект QPrinter в отдельном процессе.
Отправлено: kosproger от Июль 19, 2012, 17:46
Igors, последний вызов в строка 1026 файла qprintengine_win.cpp вот она:
Цитировать
hdc = CreateDC(reinterpret_cast<const wchar_t *>(program.utf16()),
                   reinterpret_cast<const wchar_t *>(name.utf16()), 0, devMode);
по журналу отладки последние действия:
Цитировать
Потребован шаг...
<7456-exec-step
>7456^running
dNOTE: INFERIOR RUN OK
dState changed from InferiorRunRequested(10) to InferiorRunOk(11).
>*running,thread-id="all"
>=library-loaded,id="C:\\WINDOWS\\System32\\spool\\DRIVERS\\W32X86\\3\\UNIDRV.DLL",target-name="C:\\WINDOWS\\System32\\spool\\DRIVERS\\W32X86\\3\\UNIDRV.DLL",host-name="C:\\WINDOWS\\System32\\spool\\DRIVERS\\W32X86\\3\\UNIDRV.DLL",symbols-loaded="0",thread-group="i1"
sБиблиотека C:\WINDOWS\System32\spool\DRIVERS\W32X86\3\UNIDRV.DLL загружена
>=library-loaded,id="C:\\WINDOWS\\System32\\spool\\DRIVERS\\W32X86\\3\\hpzpi5mc.dll",target-name="C:\\WINDOWS\\System32\\spool\\DRIVERS\\W32X86\\3\\hpzpi5mc.dll",host-name="C:\\WINDOWS\\System32\\spool\\DRIVERS\\W32X86\\3\\hpzpi5mc.dll",symbols-loaded="0",thread-group="i1"
sБиблиотека C:\WINDOWS\System32\spool\DRIVERS\W32X86\3\hpzpi5mc.dll загружена
d
dNON-CRITICAL TIMEOUT

Если завершить GUI, то шаг продолжает выполняться. По журналу отладки вот что происходит:
Цитировать
>=library-loaded,id="C:\\WINDOWS\\System32\\spool\\DRIVERS\\W32X86\\3\\UNIDRVUI.DLL",target-name="C:\\WINDOWS\\System32\\spool\\DRIVERS\\W32X86\\3\\UNIDRVUI.DLL",host-name="C:\\WINDOWS\\System32\\spool\\DRIVERS\\W32X86\\3\\UNIDRVUI.DLL",symbols-loaded="0",thread-group="i1"
sБиблиотека C:\WINDOWS\System32\spool\DRIVERS\W32X86\3\UNIDRVUI.DLL загружена
>=library-loaded,id="C:\\WINDOWS\\system32\\version.dll",target-name="C:\\WINDOWS\\system32\\version.dll",host-name="C:\\WINDOWS\\system32\\version.dll",symbols-loaded="0",thread-group="i1"
sБиблиотека C:\WINDOWS\system32\version.dll загружена
>=thread-exited,id="2",group-id="i1"
sЗавершился поток 2 из группы i1
>=library-loaded,id="C:\\WINDOWS\\System32\\spool\\DRIVERS\\W32X86\\3\\hpzui5mc.DLL",target-name="C:\\WINDOWS\\System32\\spool\\DRIVERS\\W32X86\\3\\hpzui5mc.DLL",host-name="C:\\WINDOWS\\System32\\spool\\DRIVERS\\W32X86\\3\\hpzui5mc.DLL",symbols-loaded="0",thread-group="i1"

........
И далее аналогичная загрузка
........

sЗакончено получение данных


Название: Re: Не создается объект QPrinter в отдельном процессе.
Отправлено: kosproger от Июль 20, 2012, 01:58
Вот, что обнаружил: в консольном приложении для чтения данных stdin из родительского процесса реализован поток. Если его убрать - инициализации принтеров производится нормально. Почему так, не понимаю...
Видимо придется как-то менять логику консоли, чтобы отвязать от получения данных из GUI.


Название: Re: Не создается объект QPrinter в отдельном процессе.
Отправлено: Igors от Июль 20, 2012, 10:58
Вот, что обнаружил: в консольном приложении для чтения данных stdin из родительского процесса реализован поток. Если его убрать - инициализации принтеров производится нормально.
Так это хорошо. А чем этот поток занят на момент зависания?


Название: Re: Не создается объект QPrinter в отдельном процессе.
Отправлено: kosproger от Июль 20, 2012, 13:56
Вот реализация потока:
datareader.h:
Код:
#ifndef DATAREADER_H
#define DATAREADER_H

#include <QThread>
#include <QTextStream>

class DataReader : public QThread
{
    Q_OBJECT
public:
    explicit DataReader(QObject *parent = 0);
    void run();
   
signals:
    void ftpExit();

    void ftpPrint();
   
public slots:
   
};

#endif // DATAREADER_H

datareader.cpp:
Код:
#include "datareader.h"

DataReader::DataReader(QObject *parent) :
    QThread(parent)
{
}

void DataReader::run() {
    QString data;
    QTextStream in(stdin);
    data = in.readLine();
    if (data.contains("stop")){
        this->ftpExit();
        fflush(stdin);
        this->quit();
    } else {
        if (data.contains("notprint")){
            this->ftpPrint();
            fflush(stdin);
        }
    }
    exec();
}

В main.cpp:
Код:
    FtpChecker *ftp = new FtpChecker(filePath,pdfPath,server,ftpUser,ftpPass,userName,fileTime,pdfTime,print);

    DataReader *reader = new DataReader();
    QObject::connect(reader,SIGNAL(finished()),&a,SLOT(quit()));
    QObject::connect(reader,SIGNAL(ftpExit()),ftp,SLOT(onFtpExit()));
    QObject::connect(reader,SIGNAL(ftpPrint()),ftp,SLOT(onFtpPrint()));
    reader->start();
    reader->moveToThread(reader->thread());

ftp - объект в котором производится непосредственно скачивание, печать и т.д.
Reader реализован для корректного выхода и отмены печати. Т.е. В зависимости от переданных параметров срабатыват сигналы ftpExit() или ftpPrint(), которые обрабатывает ftp.
На момент зависания поток пытается прочитать строку, т.е. Выполняется
Код:
data = in.readLine();

Пробовал не выделять отдельный поток, а в один запихнуть чтение stdin, работу с ftp и принтерами - то же самое.


Название: Re: Не создается объект QPrinter в отдельном процессе.
Отправлено: Bepec от Июль 20, 2012, 14:02
Сами себе и ответили. А уж обойти можно как угодно. К примеру читать по таймеру, а не readLine.

Ведь readLine ждёт знака конца строки для продолжения работы. А он вам скорее всего и не приходит.



Название: Re: Не создается объект QPrinter в отдельном процессе.
Отправлено: kosproger от Июль 20, 2012, 14:15
Bepec так ведь поток же отдельный, он не может блокировать главный цикл обработки событий, по идее...
Да и почему тогда отдельно запущенная консоль работает?


Название: Re: Не создается объект QPrinter в отдельном процессе.
Отправлено: Bepec от Июль 20, 2012, 14:18
Видимо у вас дальше по коду что-то, что требует сигнала от этого потока, ннэ?

К сожалению этого ж я не вижу и сказать ничего не могу.


Название: Re: Не создается объект QPrinter в отдельном процессе.
Отправлено: Igors от Июль 20, 2012, 14:20
На момент зависания поток пытается прочитать строку, т.е. Выполняется
Код:
data = in.readLine();
Попробовать напр так

Код
C++ (Qt)
while (!in.canReadLine())
QThread::msleep(100);
data = in.readLine();
 


Название: Re: Не создается объект QPrinter в отдельном процессе.
Отправлено: kosproger от Июль 20, 2012, 14:25
Bepec, сигналы подключены к слотам объекта класса FtpChecker в main. Выше приведен код. Реализация слотов:
Код:
void FtpChecker::onFtpExit() {
    fflush(stdin);
    qDebug("Exiting.\r\n");
    ftp->abort(); //ftp здесь - объект QFtp
    ftp->close();
    timer->deleteLater();
    ftp->deleteLater();
}

void FtpChecker::onFtpPrint() {
    canPrint = false;
}


Название: Re: Не создается объект QPrinter в отдельном процессе.
Отправлено: Bepec от Июль 20, 2012, 14:30
Скажу проще - возможно, у вас не идёт дальше, ибо ждёт от ваших же классов каких-то таинственных действий. Возможно у драйверов принтера какая то заказяка. Возможно у вас в коде далее стоит Sleep(100500) и получается Ѡ.

Саму логику работы с принтером я не представляю пока, так что могу сказать только - Возможно...


Название: Re: Не создается объект QPrinter в отдельном процессе.
Отправлено: kosproger от Июль 20, 2012, 15:42
Igors, в QTextStream нет метода canReadLine(), попробовал сделать через QFile чтение, но тогда блокируется ввод. наткнулся на эту тему: http://www.prog.org.ru/topic_10611_0.html пытаюсь что-нибудь из нее выцепить.
Bepec, работу с принтером привожу ниже. После скачивания файла с фтп, если файл имеет расширение .pdf проверяю если имя принтера указано как default либо же недоступное имя, выбираю принтер по умолчанию, создаю объект принтера, указываю название принтера, параметры печати. Для преобразования страниц pdf файла к печати используется Poppler.
Код:
        case QFtp::Get: {
            flist.first()->close();
            QString curFile = flist.first()->fileName();
            curFile.replace(0,curFile.lastIndexOf("/") + 1,"");
            qDebug(QString("File " + curFile + " downloaded.\r\n").toUtf8());
            fflush(stdout);
            if (curFile.endsWith(".pdf",Qt::CaseInsensitive)) {
                if (canPrint) {
                    Poppler::Document *doc = Poppler::Document::load(filePath + "/" + curFile);
                    bool isOk = false;
                    if (!doc || doc->isLocked()) {
                        qDebug(QString("No access to file " + filePath + "/" + curFile + "\r\n").toUtf8());
                        fflush(stdout);
                    } else {
                        QPrinterInfo *printerInf = new QPrinterInfo();
                        QString printerName;
                        if (print == "default") {
                            printerName = printerInf->defaultPrinter().printerName();
                        } else {
                            bool flag = false;
                            for (int i = 0; i < printerInf->availablePrinters().count(); i++) {
                                if (printerInf->availablePrinters().at(i).printerName() == print) {
                                    printerName = print;
                                    flag = true;
                                    break;
                                }
                            }
                            if (!flag) {
                                printerName = printerInf->defaultPrinter().printerName();
                                qDebug(QString("Printer " + print + " was not found. Using default printer.\r\n").toUtf8());
                                fflush(stdout);
                            }
                        }
                        QPrinter *printer = new QPrinter(QPrinter::HighResolution);
                        printer->setPrinterName(printerName);
                        printer->setResolution(300);
                        int i = 0;
                        while (1) {
                            Poppler::Page* pdfPage = doc->page(i);
                            if (pdfPage == 0) {
                                break;
                            } else {
                                printer->setFullPage(true);
                                printer->setPaperSize(pdfPage->pageSizeF(),QPrinter::Point);
                                switch (pdfPage->orientation()) {
                                case Poppler::Page::Seascape:
                                    printer->setOrientation(QPrinter::Landscape);
                                    break;
                                case Poppler::Page::Landscape:
                                    printer->setOrientation(QPrinter::Landscape);
                                    break;
                                case Poppler::Page::Portrait:
                                    printer->setOrientation(QPrinter::Portrait);
                                    break;
                                case Poppler::Page::UpsideDown:
                                    printer->setOrientation(QPrinter::Portrait);
                                    break;
                                }
                                QImage image = pdfPage->renderToImage(300,300);
                                if (image.isNull()) {
                                    qDebug("Poppler error: can't create image.\r\n");
                                    fflush(stdout);
                                } else {
                                    QPainter painter;
                                    if (painter.begin(printer)) {
                                        painter.drawImage(0, 0, image);
                                        if (painter.end()) {
                                            isOk = true;
                                        } else {
                                            isOk = false;
                                            break;
                                        }
                                    }
                                }
                            }
                            delete pdfPage;
                            i++;
                        }
                    }
                    delete doc;
                    if (isOk) {
                        QDir dir(pdfPath);
                        if (!dir.exists())
                            dir.mkpath(pdfPath);
                        QFile file(filePath + "/" + curFile);
                        file.rename(pdfPath + "/" + curFile);
                        qDebug(QString(curFile + " printed\r\n").toUtf8());
                        fflush(stdout);
                    } else {
                        qDebug(QString(curFile + " NOT printed\r\n").toUtf8());
                        fflush(stdout);
                    }
                } else {
                    QFile file(filePath + "/" + curFile);
                    file.rename(pdfPath + "/" + curFile);
                }
            }
            ftp->remove(curFile);
            flist.removeFirst();
            break;
        }

С принтером больше ничего.


Название: Re: Не создается объект QPrinter в отдельном процессе.
Отправлено: Igors от Июль 20, 2012, 16:47
Igors, в QTextStream нет метода canReadLine(),
А in.device()->canReadLine()? Или device() нулевое?


Название: Re: Не создается объект QPrinter в отдельном процессе.
Отправлено: kosproger от Июль 20, 2012, 16:52
Цикл работает, но то же самое, что и при QFile. Блокируется ввод. Т.е. Даже в консоли ничего не ввести... >:(


Название: Re: Не создается объект QPrinter в отдельном процессе.
Отправлено: Igors от Июль 20, 2012, 17:04
Ну хорошо, тогда может оставить in.readLine() но как-то дать ему вывод, чтобы он прочитал и больше на этой строке не стоял пока печать идет. На (самый) худой конец замочить читающий поток (terminate).


Название: Re: Не создается объект QPrinter в отдельном процессе.
Отправлено: kosproger от Июль 20, 2012, 17:10
Примерно так и пробую сейчас сделать, а именно: из GUI отправляю пустую строку ("\r\n") приложению.


Название: Re: Не создается объект QPrinter в отдельном процессе.
Отправлено: kosproger от Июль 20, 2012, 17:21
Да, получилось наконец-то!!!  :)
Передалал так:
Код:
void DataReader::run() {
    QString data;
    QTextStream in(stdin);
    while (1) {
        data = in.readLine();
        this->msleep(100);
        if (data.contains("stop")){
            this->ftpExit();
            fflush(stdin);
            this->quit();
            break;
        } else {
            if (data.contains("notprint")){
                this->ftpPrint();
                fflush(stdin);
            }
        }
    }
}

В GUI по таймеру каждые 100 мсек отправляется пустая строка.
Так и оставлю, а то замучал этот проект совсем. Хотя все же интересно, что за такая беда все-таки с принтерами...

Всем спасибо большое!! :)


Название: Re: Не создается объект QPrinter в отдельном процессе.
Отправлено: Bepec от Июль 20, 2012, 21:19
Причина то выяснена - у вас что-то в программе не так :)
Позже когда-нибудь посмотрите и скажите - как же я тогда сразу не догадался :)