Re: Serious GDI Multithreading bug while printing to metafiles



Thank you, but even GdiFlush() does not help (neither before clising
the EMF nor before deleting the DC).

Random records IN THE MIDDLE are lost.

Christian

"RMurdock" <topochicho@xxxxxxxxxxxxxx> wrote in message
news:op.t9eptlt345rr60@xxxxxxxxxxxxxxxxxxxxx
I may not be fully understanding the problem here, but what I am
getting
is that the GDI calls are made, and then the DC are deleted, but not
all
GDI calls end up in the EMF. This would seem to indicate that the DC
is
being closed before the queued call get written.

Have you tried calling GdiFlush to make sure that the GDI queue is
flushed
before calling the DeleteDC?



On Thu, 10 Apr 2008 08:24:20 -0500, Christian Kaiser <bchk@xxxxxx>
wrote:

Customers of ours reported a bug in our software that causes
metafiles
to be incorrect.

We now reduced the bug using the appended code, which is run by
multiple threads simultaneously. The code opens a printer DC, uses
that as reference DC for a new metafile DC, creates/selects a font,
draws a text, deselects and destroys the font, then destroys the
metafile DC and the printer DC. Trivial code in my eyes.

This should result in repeated calls like (decompiled to C code
using
EMF decoder, special thanks to Feng Yuan who makes that very easy):

...
hObj[1]=CreateFont(-10,0,0,0,0,0,0,0,0,0,0,0,0,"Arial");
SelectObject(hDC, hObj[1]);
const int Dx_5[]={ 5 };
ExtTextOutW(hDC, 4,4,0,NULL,L"x",1,Dx_5);
SelectObject(hDC, GetStockObject(DEVICE_DEFAULT_FONT));
DeleteObject(hObj[1]);
hObj[1]=CreateFont(-10,0,0,0,0,0,0,0,0,0,0,0,0,"Arial");
SelectObject(hDC, hObj[1]);
const int Dx_6[]={ 5 };
ExtTextOutW(hDC, 5,5,0,NULL,L"x",1,Dx_6);
SelectObject(hDC, GetStockObject(DEVICE_DEFAULT_FONT));
DeleteObject(hObj[1]);
hObj[1]=CreateFont(-10,0,0,0,0,0,0,0,0,0,0,0,0,"Arial");
SelectObject(hDC, hObj[1]);
const int Dx_7[]={ 5 };
ExtTextOutW(hDC, 6,6,0,NULL,L"x",1,Dx_7);
SelectObject(hDC, GetStockObject(DEVICE_DEFAULT_FONT));
DeleteObject(hObj[1]);
...

and most of the times it does.

When run in multiple concurrent threads, however, some of the
repetitions miss some GDI calls:

...
hObj[1]=CreateFont(-10,0,0,0,0,0,0,0,0,0,0,0,0,"Arial");
SelectObject(hDC, hObj[1]);
const int Dx_62[]={ 5 };
ExtTextOutW(hDC, 61,61,0,NULL,L"x",1,Dx_62);
SelectObject(hDC, GetStockObject(DEVICE_DEFAULT_FONT));
DeleteObject(hObj[1]);
const int Dx_63[]={ 5 };
ExtTextOutW(hDC, 62,62,0,NULL,L"x",1,Dx_63);
const int Dx_64[]={ 5 };
ExtTextOutW(hDC, 63,63,0,NULL,L"x",1,Dx_64);
SelectObject(hDC, GetStockObject(DEVICE_DEFAULT_FONT));
const int Dx_65[]={ 5 };
ExtTextOutW(hDC, 64,64,0,NULL,L"x",1,Dx_65);
const int Dx_66[]={ 5 };
ExtTextOutW(hDC, 65,65,0,NULL,L"x",1,Dx_66);
const int Dx_67[]={ 5 };
ExtTextOutW(hDC, 66,66,0,NULL,L"x",1,Dx_67);
const int Dx_68[]={ 5 };
ExtTextOutW(hDC, 67,67,0,NULL,L"x",1,Dx_68);
const int Dx_69[]={ 5 };
ExtTextOutW(hDC, 68,68,0,NULL,L"x",1,Dx_69);
const int Dx_70[]={ 5 };
ExtTextOutW(hDC, 69,69,0,NULL,L"x",1,Dx_70);
const int Dx_71[]={ 5 };
ExtTextOutW(hDC, 70,70,0,NULL,L"x",1,Dx_71);
const int Dx_72[]={ 5 };
ExtTextOutW(hDC, 71,71,0,NULL,L"x",1,Dx_72);
const int Dx_73[]={ 5 };
ExtTextOutW(hDC, 72,72,0,NULL,L"x",1,Dx_73);
...

This happens at least in Windows XP and in Vista.

Strange is, the CreateFont(), SelectFont(), ..., DeleteFont() is
being
executed in the DC correctly, and the DC state reflects this (we can
see this in our application, which uses the selected font for some
layouting - these calculations are correct). The GDI calls are just
not stored in the metafile. There is no failure in CreateFont or
SelectFont (I left out of the checking code in the demonstration
code
below, for clarity reasons).

Next astonishing thing is that setting the ProcessAffinityMask to
one
processor does not help. It still happens - this, for me, was really
unexpected.

When the code below is executed multiple times, it should create
similar EMF files - but they all vary in size as indication there's
something going wrong. Looking into them, it can be seen that there
are a lot of missing records.

Serializing the whole sequence is a possible solution (a part, for
example, only CreateFont/SelectFont does not help), but scales
extremely bad with multiple processors ;-(. Especially when the GDI
calls are not so easily locateable, but all over thousands of code
lines.

Is a workaround known? This is a serious problem in multithreaded
printing (using metafiles).

Christian

------------------------------
PRINTDLG pd = {0};
TCHAR szFile[MAX_PATH];

_stprintf(szFile,"test_%08x.emf",::GetCurrentThreadId());

pd.lStructSize = sizeof(pd);
pd.Flags = PD_RETURNDC | PD_RETURNDEFAULT;
::PrintDlg(&pd);

RECT rcPage = {0,0,10000,10000};
HDC hMetaDC = ::CreateEnhMetaFile(pd.hDC,szFile,&rcPage,"Hallo");

for (int i = 0; i < 2000; ++i)
{
HFONT hFont = ::CreateFont(
-10,
0,
0,
0,
0,
0,
0,
0,
ANSI_CHARSET,
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,
0,
"Arial");
HFONT hOldFont = SelectFont(hMetaDC,hFont);

::ExtTextOut(hMetaDC,
i,
i,
0,
NULL,
"x",
1,
NULL);

SelectFont(hMetaDC,hOldFont);
DeleteFont(hFont);
}
HENHMETAFILE hEMF = ::CloseEnhMetaFile(hMetaDC);
::DeleteObject(hEMF);

::DeleteDC(pd.hDC);







--
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/


.



Relevant Pages

  • Re: Serious GDI Multithreading bug while printing to metafiles
    ... There's nothing thread safe about GDI calls. ... metafile DC and the printer DC. ... When run in multiple concurrent threads, however, some of the ... Strange is, the CreateFont(), SelectFont, ..., DeleteFontis being ...
    (microsoft.public.win32.programmer.gdi)
  • Re: Serious GDI Multithreading bug while printing to metafiles
    ... I may not be fully understanding the problem here, but what I am getting is that the GDI calls are made, and then the DC are deleted, but not all GDI calls end up in the EMF. ... Have you tried calling GdiFlush to make sure that the GDI queue is flushed before calling the DeleteDC? ... metafile DC and the printer DC. ... Strange is, the CreateFont(), SelectFont, ..., DeleteFontis being ...
    (microsoft.public.win32.programmer.gdi)
  • GDI+ Flat API EMF Questions/Issues
    ... I'm using the GDI+ flat API from classic VB. ... GdipLoadImageFromFile returns a status OK when reading an EMF (enhanced ... Am I being fooled by the status OK returned by GdipLoadImageFromFile? ... drawing directly to the metafile with vector commands. ...
    (microsoft.public.dotnet.framework.drawing)
  • Re: Select polygon on EMF on MouseOver
    ... EMF I produce with a opensource conversion tool, ... The currently selected pen and brush object will have an effect on the hit-testing so my advice would be to create a ... Mike, thanks a lot for your help. ... EnumMetaFileProcto determine which GDI function correspond to the ...
    (microsoft.public.vb.general.discussion)
  • Re: Cutlines im Report
    ... Vektordaten - aber nicht die von VFP erzeugten.< ... Aus der Microsoft EMF Specification ... This is a specification of the Enhanced Metafile Format structure, ...
    (microsoft.public.de.fox)