snowie2000 / mactype

Better font rendering for Windows.
https://mactype.net
GNU General Public License v3.0
9.86k stars 437 forks source link

Invoking MacType's window hooks programatically #684

Closed shadeMe closed 1 year ago

shadeMe commented 4 years ago

I have a regular bare-Win32/non-MFC program that has trouble with MacType. It instantiates multiple windows/modeless dialogs at startup, most of which are correctly hooked and updated by MacType. However, a couple of dialogs (created with CreateDialogParam) consistently are unaffected by MacType's hooks. I have been unable to determine why this is the case - although it reeks of a race condition - but I'd at least like to alleviate this by somehow manually invoking MacType's window hooks, etc on those specific dialogs after their initialization process is complete.

Is there some kind of IPC mechanism with which I can forcefully "refresh" or reinitialize the hooking process?

snowie2000 commented 3 years ago

There is no way to do it so far. MacType doesn't have any rendering APIs exposed. (It does have some hot-reload and re-config APIs)

The way MacType works is by hooking into the standard windows GDI text rendering process and it's thread-safe. If your application is partially working with MacType, the whole application affected. It's just for some reason, mactype decided to not intercept your text output, either because it's drawing with pixelated font or it's monochrome.

You can post a screenshot of what the situation is and we could try to figure it out.

shadeMe commented 3 years ago

Screenshot 2020-11-24 143013

During application startup, the main window (1), its menu (2) and, windows 5 & 6 were automatically loaded. Windows 3, 4, 7 & 8 were opened after the startup process ended. 1, 2, 4 & 8 are correctly handled by MacType but the rest aren't. I'm beginning to believe that that this behaviour might be tied to how each of those dialog templates are instantiated, as the ones that are correctly handled by MacType work consistently, i.e., even after being closed and re-opened, and vice-versa.

Funnily enough, there was at least one old version of MacType (from, perhaps, a couple a years ago) where it did correctly handle all windows (or at least those shown in the screenshot). However, it was very inconsistent.

More context: The host Win32 application in question is proprietary. I use DLL injection to load my own code which significantly alters the host's using low-level API hooking and other shenanigans. My code also hosts the .NET CLR runtime to execute managed code in-process. The managed code is built using WinForms and some WPF components, both of which are more or less handled by MacType (see below). To ensure that this issue was not a corner-case caused by non-trivial interaction of all of the above, I tried to run the base app without my modifications. And indeed, the same issue occurs (down to the same dialog windows not being themed).

Screenshot 2020-11-24 144212

Let me know if you need more information. I reckon a debug build that logs verbose information might help zero-in on the root cause.

snowie2000 commented 3 years ago

Ok, As far as I can see, those windows that didn't get rendered are the ones that use pixelated font.

To be sure about it, I suggest you use another side project of me called 'whichfont' it's available here: https://github.com/snowie2000/WhichFont

Turn off mactype completely, and restart your program from whichfont, it should then tells you what fonts the program is using, and highlights the font name that being actively used to paint the window in real time.

shadeMe commented 3 years ago

Screenshot 2020-11-24 153914

Yeah, looks like those unhandled dialogs use MS Sans Serif.

snowie2000 commented 3 years ago

MS Sans Serif is not a real font, it refers to other real font via the registry, but you can still substitute it with Mac type.

Or, if you have access to the source code of the application, changing the font of the dialog would be ideal.

shadeMe commented 3 years ago

I ended up using Windows' built-in font substitution feature to override all variants of MS Sans/Serif; that fixes the issue by-and-large, many thanks! However, some WinForms controls (which should be using GDI/++ for rendering) are still not correctly handled:

Screenshot 2020-11-25 113237

In the screenshot above, only the list view column headers and the group box text are handled. No of the others seem to be though. All controls in that dialog use the default WinForms Control font: [Font: Name=Segoe UI, Size=8.25, Units=3, GdiCharSet=0, GdiVerticalFont=False] (printed it out directly in my code at runtime). Unfortunately, I can't use WhichFont to debug this dialog as it's injected code (the loader spawns a child process, which your tool doesn't handle).

snowie2000 commented 3 years ago

.net Winforms use DirectWrite for text rendering, so the directwrite support must be enabled in your profile.

GDIPlus is definitely not supported. I've tried to support it once, but the text engine is very poorly documented. There is no way to simulate it accurately enough.

shadeMe commented 3 years ago

.net Winforms use DirectWrite for text rendering, so the directwrite support must be enabled in your profile.

Ah, does it? I was under the impression that WinForms was backed by GDI (or GDI+, not sure about that) while WPF was built on top of DirectX/DirectWrite. In any event, my profile does have DirectWrite support enabled and the latter does get correctly rendered (the text editor in the previous screenshot).

GDIPlus is definitely not supported. I've tried to support it once, but the text engine is very poorly documented. There is no way to simulate it accurately enough.

I see. Are there any plans to implement support for attaching to existing processes in WhichFont? That might help with debugging this issue.

sammilucia commented 3 years ago

Ah, does it? I was under the impression that WinForms was backed by GDI (or GDI+, not sure about that) while WPF was built on top of DirectX/DirectWrite. In any event, my profile does have DirectWrite support enabled and the latter does get correctly rendered (the text editor in the previous screenshot).

I think it depends on which version of WinForms it is (i.e. which library they come from)... Old versions will probably use MS Sans Serif, and new will use Segoe Ui with DirectWrite.

There are a few INIs in the default install that already have DirectWrite configured - ChicoThorn, Clean Dark, extratype, and mufunyo. Just be aware the DW rendering will look different from the GDI rendering no matter what you do.

snowie2000 commented 3 years ago

You may try to set your parameters to extreme values, like super dark or super light so that you can distinguish them better.

shadeMe commented 3 years ago

You may try to set your parameters to extreme values, like super dark or super light so that you can distinguish them better.

Screenshot 2020-11-27 110516 With RenderWeight set to a 20. Also tried to set the DirectWrite parameters to extreme values, but it didn't affect the above dialog.