Как устранить зависание при печати Quick Report в потоке
Компилятор: C++ Builder
Для этого необходимо вызывать методы и свойства VCL через Synchronize().
Следующий пример демонстрирует это:
//-------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
#include "Unit2.h"
#pragma package(smart_init)
//-------------------------------------------------------------------
// Метод Synchronize используется следующим образом:
//
// Synchronize(UpdateCaption);
//
// где UpdateCaption выглядит примерно так:
//
// void __fastcall PrintQReport::UpdateCaption()
// {
// Form1->Caption = "Updated in a thread";
// }
//-------------------------------------------------------------------
__fastcall PrintQReport::PrintQReport(bool CreateSuspended)
: TThread(CreateSuspended)
{
}
//-------------------------------------------------------------------
void __fastcall PrintQReport::Execute()
{
//---- Поместите сюда код потока ----
Synchronize(Print);
}
//-------------------------------------------------------------------
void __fastcall PrintQReport::Print()
{
Form1->QuickRep1->Print();
}
//-------------------------------------------------------------------
Для изменения размера бумаги на принтере, необходимо несколько раз вызвать API функцию DocumentProperties(). Для начала, чтобы открыть принтер (и получить его дескриптор), вызываем функцию OpenPrinter(). Далее вызываем DocumentProerties() с нулевым параметром fMode, чтобы получить размер в байтах, необходимый для структуры DEVMODE. Выделяем необходимое количество памяти, а затем снова вызываем DocumentProperties(), чтобы получить указатель на структуру, используемую принтером. При помощи этого указателя изменяем необходимые нам поля. Затем опять вызываем DocumentProperties(), записать изменения в DEVMODE и передать её в функцию CreateDC().
//---------------------------------------------------------------------------
void __fastcall TForm1::PrintButtonClick(TObject *Sender)
{
// получаем имя дефолтового принтера, драйвер и порт
char *def_string = "no printer";
char buffer[MAX_PATH];
GetProfileString("windows", "device", def_string,
buffer, MAX_PATH);
AnsiString Abuffer(buffer);
AnsiString Device, Driver, Port;
// парсим из буфера определённые свойства
int first_comma = Abuffer.Pos(",");
Device = Abuffer.SubString(1, first_comma - 1);
Abuffer = Abuffer.SubString(first_comma + 1,
Abuffer.Length() - first_comma);
int second_comma = Abuffer.Pos(",");
Driver = Abuffer.SubString(1, second_comma - 1);
Port = Abuffer.SubString(second_comma + 1,
Abuffer.Length() - second_comma);
// открываем принтер
HANDLE HPrinter;
if (OpenPrinter(Device.c_str(), &HPrinter, NULL))
{
// вызываем DocumentProerties() с нулевым параметром fMode
// чтобы получить количество необходимых байт
long int num_bytes;
num_bytes = DocumentProperties(NULL, HPrinter, Device.c_str(),
NULL, NULL, 0);
// выделяем память
unsigned char *buffer = new unsigned char[num_bytes];
// опять вызываем DocumentProperties(), на сей раз, чтобы
// получить информацию об устройстве
DocumentProperties(NULL, HPrinter, Device.c_str(),
(PDEVMODE)buffer, NULL, DM_OUT_BUFFER);
PDEVMODE pdm = (PDEVMODE)buffer;
// изменяем соответствующие поля
pdm->dmPaperSize = DMPAPER_10X14; // например
// говорим Windows, какие поля мы изменили
pdm->dmFields = pdm->dmFields | DM_PAPERSIZE;
// ещё раз вызываем DocumentProperties(), чтобы получить окончательный
// DEVMODE который будет передан в функцию CreateDC()
DocumentProperties(NULL, HPrinter, Device.c_str(),
pdm, pdm, DM_OUT_BUFFER | DM_IN_BUFFER);
// создаём контекст устройства принтера
HDC HPrinterDC = CreateDC(Driver.c_str(), Device.c_str(),
NULL, pdm);
if (HPrinterDC)
{
DOCINFO di;
di.cbSize = sizeof(DOCINFO);
di.lpszDocName = "Test Print";
di.lpszOutput = (LPTSTR) NULL;
di.lpszDatatype = (LPTSTR) NULL;
di.fwType = 0;
// начинаем печать
if (StartDoc(HPrinterDC, &di))
{
if (StartPage(HPrinterDC))
{
float fLogPelsX1, fLogPelsY1;
fLogPelsX1 =
(float)GetDeviceCaps(HPrinterDC, LOGPIXELSX);
fLogPelsY1 =
(float)GetDeviceCaps(HPrinterDC, LOGPIXELSY);
RECT R = Rect(0, 0, fLogPelsX1 * 8.5, fLogPelsY1 * 11);
// печатаем любой текст
::DrawText(HPrinterDC, Memo1->Text.c_str(),
Memo1->Text.Length(), &R,
DT_LEFT | DT_EDITCONTROL | DT_WORDBREAK);
EndPage(HPrinterDC);
}
EndDoc(HPrinterDC);
}
DeleteDC(HPrinterDC);
}
delete [] buffer;
ClosePrinter(HPrinter);
}
}