From: Dmitry Timoshkov dmitry@baikal.ru
FillPath() for a EMF hdc has its own handler EMFDC_FillPath which calls NtGdiPathToRegion() as part of its workflow. NtGdiPathToRegion() on success sets dc->path to NULL. NtGdiFillPath() fails and sets last error to ERROR_CAN_NOT_COMPLETE if dc->path is NULL, so calling FillPath() on a EMF hdc currently always fails with ERROR_CAN_NOT_COMPLETE.
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/gdi32/dc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/gdi32/dc.c b/dlls/gdi32/dc.c index cc39f2794e2..3a88e4749c2 100644 --- a/dlls/gdi32/dc.c +++ b/dlls/gdi32/dc.c @@ -2182,7 +2182,7 @@ BOOL WINAPI FillPath( HDC hdc )
if (!(dc_attr = get_dc_attr( hdc ))) return FALSE; if (dc_attr->print) print_call_start_page( dc_attr ); - if (dc_attr->emf && !EMFDC_FillPath( dc_attr )) return FALSE; + if (dc_attr->emf) return EMFDC_FillPath( dc_attr ); return NtGdiFillPath( hdc ); }
Jacek Caban (@jacek) commented about dlls/gdi32/dc.c:
if (!(dc_attr = get_dc_attr( hdc ))) return FALSE; if (dc_attr->print) print_call_start_page( dc_attr );
- if (dc_attr->emf && !EMFDC_FillPath( dc_attr )) return FALSE;
- if (dc_attr->emf) return EMFDC_FillPath( dc_attr );
I think that the bouds rect update should be moved to `EMFDRV_FillPath`, avoiding the call to `NtGdiPathToRegion` in gdi32.
On Sat Mar 8 21:26:10 2025 +0000, Jacek Caban wrote:
I think that the bouds rect update should be moved to `EMFDRV_FillPath`, avoiding the call to `NtGdiPathToRegion` in gdi32.
Is this testable? We do have StrokeAndFillPath call for emfdc in tests, and it does not look like it's failing. Or it's an issue with last error only?
On Sat Mar 8 21:28:51 2025 +0000, Nikolay Sivov wrote:
Is this testable? We do have StrokeAndFillPath call for emfdc in tests, and it does not look like it's failing. Or it's an issue with last error only?
I guess that Dmitry's use case is on a printer DC, I think it wouldn't fail on EMF DC. So yes, it's testable but more tricky.
The difference between bounds rect update in win32u vs. gdi32 is testable too, but the test isn't that interesting. I didn't check this specifically, but I remember seeing that generally if you use win32u directly on EMF DC, it's not recorded but bounds are updated.
FWIW, the bounds rect on native seems more generic than just EMF/printer DC. I recall finding that something like `NtGdiGetBoundsRect` (or something similar) has a flag to get what we need and it works on other DC types too. We don't have that yet.
On Sat Mar 8 21:41:13 2025 +0000, Jacek Caban wrote:
I guess that Dmitry's use case is on a printer DC, I think it wouldn't fail on EMF DC. So yes, it's testable but more tricky. The difference between bounds rect update in win32u vs. gdi32 is testable too, but the test isn't that interesting. I didn't check this specifically, but I remember seeing that generally if you use win32u directly on EMF DC, it's not recorded but bounds are updated. FWIW, the bounds rect on native seems more generic than just EMF/printer DC. I recall finding that something like `NtGdiGetBoundsRect` (or something similar) has a flag to get what we need and it works on other DC types too. We don't have that yet.
Yes, the bug appears during printing. So, what would be a recommended way to proceed with this? Or should I leave it for later when appropriate functionality on win32u side is implemented?
On Sun Mar 9 07:32:58 2025 +0000, Dmitry Timoshkov wrote:
Yes, the bug appears during printing. So, what would be a recommended way to proceed with this? Or should I leave it for later when appropriate functionality on win32u side is implemented?
I missed the fact that we also need the bounds rect for the record itself, not only to update DC bound rect. I guess we need to get it somehow without invalidating DC path.
How should we proceed here? Failing FillPath() on a printer DC is a pretty serious problem. In case it would be helpful the bug could be reproduced with sample application attached to the bug https://bugs.winehq.org/show_bug.cgi?id=57889 (it requires .Net 4.72 or 4.8).