c++ - 工作线程中的 GDI 打印机设备上下文随机失败

标签 c++ multithreading c++builder gdi

我设法创建了一个基于 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/

相关文章:

c++ - 字符串到字符 - C++

c++ - 如何通过继承专门化复杂模板 - C++

.net - 使用.NET 5 CancellationToken调用可以在主线程上超时的方法

c++ - 发布者和消费者线程之间通过堆栈共享数据

components - 如何备份我的 C++ Builder 组件安装?

c++ - 为什么这个 for 循环不会中断

c++ - C++ 中的赋值运算符重载

c# - 何时使用 BlockingCollection 以及何时使用 ConcurrentBag 而不是 List<T>?

c++builder - 使用 gnuplot 制作带有数据文件的电影

visual-c++ - vtable 中重载方法的顺序(在 win32 上)