Discussions related to Visual Prolog
Post Reply
Harrison Pratt
VIP Member
Posts: 458
Joined: 5 Nov 2000 0:01

Problem using Font generated from HDC in subordinate clause

Post by Harrison Pratt »

If I pass the Hardware Device Context (HDC) from a dialog's onPaint/3 clause to a subordinate clause and use that HDC to create a font (or a copy of that font) then using that font generates an ObjectBusy exception in graphics:drawStringAt/5.

Of course, one can easily pass the Font to the subordinate clause as in testDraw/2 and avoid the issue.

Is this a problem with my understanding how fonts work in ViP, or is it a bug?

Code: Select all

GDI+ exception       apiFunctionName = drawStringIn     StatusMessage = ObjectBusy     StatusCode = 4   gdiplusException (gdiplus) graphics::drawStringIn pfc\gui\gdiplus\graphics\graphics.pro(539,9) ---------------------------------------- c:\users\hwpra\appdata\roaming\visual prolog\11\pfc\exception\exception.pro(197) c:\users\hwpra\appdata\roaming\visual prolog\11\pfc\gui\gdiplus\gdiplussupport\gdiplussupport.pro(169) testdialogf5\testdialogf5.pro(36)


Here is test code to demonstrate the problem:

Code: Select all

predicates     onPaint : window::paintResponder. clauses     onPaint(_Source, _Rectangle, GDI) :-         HDC = GDI:getNativeGraphicContext(IsReleaseNeeded),         G = graphics::createFromHDC(HDC),         %         F0 = font::createFromHDC(HDC),         G:drawStringAt(F0, solidBrush::create(gdiplus_native::black), gdiplus_native::pointF(5, 5), predicate_fullname(),             stringFormat::create(0, locale_native::lang_english)),         testDraw(G), % Raises exception %        testDraw(G, F0),         %         GDI:releaseNativeGraphicContext(HDC, IsReleaseNeeded).   predicates     testDraw : (graphics G). % either TestMode raises exception     testDraw : (graphics G, font Font).   clauses     testDraw(G) :-         TestMode = 1, % get font from HDC if = 1, % create copy of font from HDC if = 2         HDC = G:getHDC(),         if TestMode = 1 then             Font = font::createFromHDC(HDC)         elseif TestMode = 2 then             % create a copy of the HDC font             HdcFont = font::createFromHDC(HDC),             FF = HdcFont:fontfamily,             Size = HdcFont:size,             FS = HdcFont:style,             Font = font::createFromFontFamily(FF, Size, FS, gdiplus_native::unitPixel)         end if,         S = predicate_fullname(),         G:drawStringAt(Font, solidBrush::create(gdiplus_native::darkRed), gdiplus_native::pointF(40, 40), S,             stringFormat::create(0, locale_native::lang_english)).       testDraw(G, Font) :-         S = predicate_fullname(),         G:drawStringAt(Font, solidBrush::create(gdiplus_native::darkRed), gdiplus_native::pointF(40, 40), S,             stringFormat::create(0, locale_native::lang_english)).
User avatar
Thomas Linder Puls
VIP Member
Posts: 1457
Joined: 28 Feb 2000 0:01

Re: Problem using Font generated from HDC in subordinate clause

Post by Thomas Linder Puls »

The font's you are working with here are GDI+ fonts. I think the problem you experience is described here Font::Font(HDC) method.

I have copied the relevant text here:
In most cases when you obtain a device context handle by calling the GetHDC method of a Graphics object, the device context will not have a font selected. ...
So the problem is actually in the HDC you are obtaining from G.

By the way GDI+ is rather inefficient/slow (which may not be a problem in most contexts). Direct2D & DirectWrite on the other hand is supposedly rather efficient, but requires different approaches for dealing with fonts and other such "resources". There is a demo direct2DDemo among the demo examples.

We kind of regret that we spent time on importing and using GDI+ instead of using Direct2D/DirectWrite.
Our Direct2D/DirectWrite import is based on a reengineering made in the Wine project.
Regards Thomas Linder Puls
PDC
Harrison Pratt
VIP Member
Posts: 458
Joined: 5 Nov 2000 0:01

Re: Problem using Font generated from HDC in subordinate clause

Post by Harrison Pratt »

Thank you, Thomas -- that's very clear.
What confused me was being able to get and use a font from HDC in onPaint/3 but not in testDraw/1 when the debugger showed identical handles to the font to be used in both clauses.
User avatar
Thomas Linder Puls
VIP Member
Posts: 1457
Joined: 28 Feb 2000 0:01

Re: Problem using Font generated from HDC in subordinate clause

Post by Thomas Linder Puls »

Which font handles are identical?
Regards Thomas Linder Puls
PDC
User avatar
Thomas Linder Puls
VIP Member
Posts: 1457
Joined: 28 Feb 2000 0:01

Re: Problem using Font generated from HDC in subordinate clause

Post by Thomas Linder Puls »

This gives the same problem:

Code: Select all

predicates     onPaint : window::paintResponder. clauses     onPaint(_Source, _Rectangle, GDI) :-         HDC = GDI:getNativeGraphicContext(IsReleaseNeeded),         G = graphics::createFromHDC(HDC),         S = predicate_fullname(),         F1 = font::createFromHDC(HDC),         G:drawStringAt(F1, solidBrush::create(gdiplus_native::black), gdiplus_native::pointF(10, 120), S),         F2 = font::createFromHDC(HDC),         G:drawStringAt(F2, solidBrush::create(gdiplus_native::darkRed), gdiplus_native::pointF(10, 140), S),         GDI:releaseNativeGraphicContext(HDC, IsReleaseNeeded).
So it seems that the problem is that you can only make one font from an device context.

You should know that it is Microsoft that have sets the rules for these things not us. (And that such rules and restrictions can be just as surprising to us).
Regards Thomas Linder Puls
PDC
Harrison Pratt
VIP Member
Posts: 458
Joined: 5 Nov 2000 0:01

Re: Problem using Font generated from HDC in subordinate clause

Post by Harrison Pratt »

That code above executes normally for me:
Screenshot 2024-11-30 085117.png
Screenshot 2024-11-30 085117.png (6.44 KiB) Viewed 74485 times
It seems that the problem occurs when creating fonts from an HDC retrieved from a graphics object. The code below reproduces the original problem without the complication of a subordinate object.

Code: Select all

    onPaint(_Source, _Rectangle, GDI) :-         HDC0 = GDI:getNativeGraphicContext(IsReleaseNeeded),         G = graphics::createFromHDC(HDC0),         HDC1 = G:getHDC(),         S = predicate_fullname(),         F0 = font::createFromHDC(HDC0),         F1 = font::createFromHDC(HDC1),         F2 = font::createFromHDC(HDC1),         nothing(F0, F1, F2),         %-- attempting to use the fonts will raise an exception:         G:drawStringAt(F0, solidBrush::create(gdiplus_native::green), gdiplus_native::pointF(10, 100), S),         G:drawStringAt(F1, solidBrush::create(gdiplus_native::black), gdiplus_native::pointF(10, 120), S),         G:drawStringAt(F2, solidBrush::create(gdiplus_native::darkRed), gdiplus_native::pointF(10, 140), S),         GDI:releaseNativeGraphicContext(HDC0, IsReleaseNeeded).
Fonts F1 and F2 have identical handles.
You apparently can create those fonts ... but you can't use them!
User avatar
Thomas Linder Puls
VIP Member
Posts: 1457
Joined: 28 Feb 2000 0:01

Re: Problem using Font generated from HDC in subordinate clause

Post by Thomas Linder Puls »

If I understand you correctly: you and I don't have same behavior. And that is unpleasant because then you cannot really be sure whether your code is "good or bad".

Anyway it seems safest to stick to only using the first font you create.
Regards Thomas Linder Puls
PDC
Harrison Pratt
VIP Member
Posts: 458
Joined: 5 Nov 2000 0:01

Re: Problem using Font generated from HDC in subordinate clause

Post by Harrison Pratt »

"If you try and take a cat apart to see how it works,
the first thing you have on your hands is a non-working cat."
--Douglas Adams
Post Reply