我设法创建了一个基于 GDI 的位图文件打印机例程。它工作稳定,没有任何泄漏。唯一的缺点当然是它在后台处理程序传输过程中卡住了 UI。解决方案尝试将打印例程移动到工作线程中。这是代码(删除了错误检查):
void __fastcall PRINT_THREAD::Execute()
{
while(!Terminated)
{
Synchronize(&TalkToOwningThread);
if(PrintFilePath!="") PrintImage(PrintFilePath);
Sleep(10);
}
}
void __fastcall PRINT_THREAD::PrintImage(WideString PrintFilePath)
{
HDC hDC;
DOCINFO di;
int w,h;
bool success=true;
TCHAR szString[32] = TEXT("Printed from a thread");
WideString PrinterName="FinePrint";
TBitmap *bmp = new TBitmap();
TPicture *pic = new TPicture();
hDC=CreateDC(TEXT("WINSPOOL"),PrinterName.c_bstr(),NULL,NULL);
w=GetDeviceCaps(hDC, HORZRES);
h=GetDeviceCaps(hDC, VERTRES);
SecureZeroMemory(&di,sizeof(DOCINFO));
di.cbSize = sizeof(DOCINFO);
di.lpszDocName = TEXT("Print Job");
StartDoc(hDC,&di);
StartPage(hDC);
try
{
pic->LoadFromFile(PrintFilePath);
bmp->Width=w; // set the bitmap dimensions to the printer dimensions
bmp->Height=h;
// fill the bitmap with 1:1 print content
bmp->Canvas->StretchDraw(TRect(0,0,w-1,h-1),pic->Graphic);
}
catch(...){success=false;}
if(success)
{
BitBlt(hDC,0,0,w,h, bmp->Canvas->Handle,0,0, SRCCOPY);
TextOut(hDC,0,100,szString,lstrlen(szString));
}
EndDoc(hDC);
if(hDC) DeleteDC(hDC);
delete pic;
delete bmp;
结果:
- 每个打印调用都通过打印机在页面上生成 - OK
- 10 页中只有大约 2 页包含位图 - 不好
- 所有页面都包含测试行 - OK
- 每次调用都会添加一个 GDI 资源(任务管理器)- 不行
我已经尝试将 CreateDC/DeleteDC 函数移回主线程并将 hDC 转移到工作线程 - 结果相同。
有什么想法可以让这只动物奔跑吗?
环境: C++Builder 10.1 柏林,Windows10,16GB
谢谢。
最佳答案
按照雷米的建议,我添加了锁定/解锁对:
TBitmap *bmp = new TBitmap();
TPicture *pic = new TPicture();
bmp->Canvas->Lock();
----
----
EndPage(hDC);
EndDoc(hDC);
bmp->Canvas->Unlock();
if(hDC) DeleteDC(hDC);
delete pic;
delete bmp;
最后,这只动物运行得非常顺利 - 不再丢失图形,也不再出现 GDI 泄漏。
关于c++ - 工作线程中的 GDI 打印机设备上下文随机失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53696554/