Recent

Author Topic: Unicode characters on Win9x with TextOutW  (Read 3188 times)

palacs

  • New Member
  • *
  • Posts: 21
Unicode characters on Win9x with TextOutW
« on: July 03, 2018, 11:53:14 pm »
I need to create an application that deals properly with unicode text on Win9x. Windows 98 would be enough at first. As far as I read, Lazarus never supported MSLU (unicows.dll) and has just phased out Windows 98 support recently. Of course this doesn't mean we can't print out Unicode characters in Windows 98 from an application created with Lazarus.

I started experimenting with Lazarus 1.2.6. This is an older version which has an IDE running well on Windows 98 and also the compiled code performs pretty well on the same system. I created a test application that directly calls windows.TextOutW with proper parameters. It did work so it displayed unicode characters on Windows 98 (cyrillic, greek characters), unlike any other function (like DrawText, TextRect, TextOut, etc.). Still without unicows.dll or MSLU!

Okay, now I can custom-draw any unicode text onto the canvas of any widget. However, I want all widgets to do this, without rewriting or sub-classing them (and lose them from the GUI designer).

I had to realize that I need to modify the LCL a bit to be able to do that. So I went on by replacing a TextOut call in TCustomLabel which worked perfectly. All my labels have become unicode under Windows 98. However, this is still not enough. I want all elements, that draw text to any widget, to do it with TextOutW.

So, let's see TLabel. It comes from TCustomLabel that has a Paint function in customlabel.inc. It calls TCanvas.TextRect of the Graphics unit. TCanvas.TextRect creates a virtual rectangle for the text, does some coordinate calculations, then calls DrawText in winapi.inc. It calls WidgetSet.DrawText with the same parameters. Unfortunately, this is the point I gave up messing around in the abyss of LCL. Someone who is experienced enough, please tell me where should I modify the LCL in order to redirect all its wrapped text-drawing calls to TextOutW instead of other WINAPI functions which won't deal with unicode properly on Win9x.

Thanks in advance

taazz

  • Hero Member
  • *****
  • Posts: 5363
Re: Unicode characters on Win9x with TextOutW
« Reply #1 on: July 04, 2018, 01:14:56 am »
I need to create an application that deals properly with unicode text on Win9x. Windows 98 would be enough at first. As far as I read, Lazarus never supported MSLU (unicows.dll) and has just phased out Windows 98 support recently. Of course this doesn't mean we can't print out Unicode characters in Windows 98 from an application created with Lazarus.

I started experimenting with Lazarus 1.2.6. This is an older version which has an IDE running well on Windows 98 and also the compiled code performs pretty well on the same system. I created a test application that directly calls windows.TextOutW with proper parameters. It did work so it displayed unicode characters on Windows 98 (cyrillic, greek characters), unlike any other function (like DrawText, TextRect, TextOut, etc.). Still without unicows.dll or MSLU!

Okay, now I can custom-draw any unicode text onto the canvas of any widget. However, I want all widgets to do this, without rewriting or sub-classing them (and lose them from the GUI designer).

I had to realize that I need to modify the LCL a bit to be able to do that. So I went on by replacing a TextOut call in TCustomLabel which worked perfectly. All my labels have become unicode under Windows 98. However, this is still not enough. I want all elements, that draw text to any widget, to do it with TextOutW.

So, let's see TLabel. It comes from TCustomLabel that has a Paint function in customlabel.inc. It calls TCanvas.TextRect of the Graphics unit. TCanvas.TextRect creates a virtual rectangle for the text, does some coordinate calculations, then calls DrawText in winapi.inc. It calls WidgetSet.DrawText with the same parameters. Unfortunately, this is the point I gave up messing around in the abyss of LCL. Someone who is experienced enough, please tell me where should I modify the LCL in order to redirect all its wrapped text-drawing calls to TextOutW instead of other WINAPI functions which won't deal with unicode properly on Win9x.

Thanks in advance
wrong control. Tlabel is based on TGraphicControl which is in fact a custom drawn control not a native one. Try the same with a native control a simple one like tedit and see if changing only textout to textoutw is enough (long story short no its not). If it was that simple it would have been part of the lcl already.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

palacs

  • New Member
  • *
  • Posts: 21
Re: Unicode characters on Win9x with TextOutW
« Reply #2 on: July 04, 2018, 09:23:21 am »
To be exact, TCustomLabel is based on TGraphicControl and TLabel is on TCustomLabel. Of course, TLabel comes from TGraphicControl but not directly.

If it was that simple it would have been part of the lcl already.
I don't think it wasn't because "it's way too complex". The simple question is, why would it have been implemented? TextOutW is useless in environments that support unicode natively, like all Windows from version 2000. The Windows 9x support has just been phased out from the LCL and has never been an important aspect of maintaining the LCL. To be honest I don't understand why, a plenty of people develop for these old platforms on this forum, however developing using LCL and maintaining it are two different stories. All in all, what I think I miss here is understanding two things.

1. How TextRect and DrawText do wrap TextOut?
2. How could I rewrite TextOut to call TextOutW? The problem is that in winapi.inc it is not referenced. If I pull it in by adding windows to the uses block, it would mess up everything. I don't understand how the LCL is structured so I can't really figure out where I should change this.
« Last Edit: July 04, 2018, 09:37:14 am by palacs »

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 7438
Re: Unicode characters on Win9x with TextOutW
« Reply #3 on: July 04, 2018, 10:35:01 am »
(just fyi Windows 98 support was formally abandoned on January 1st 2012 with the release of FPC 2.6.0.

However during the 2.6.x branch patches to fix things or alternate codepaths were sometimes maintained because the number of problem points was low.

With the unicode support in 3.0 however that became undoable, so then windows 98 was also practically abandoned

The reasons for the deprecation was the lack of even a semblance of regular win9x maintenance. The core developers had no win98 systems anymore, and nobody took over. Bugs against windows 98 compatibility that had been in trunk for the better more than an year, only came out on final release (and even the RC was ignored).

During the 2.4.x cycle, half of the post branching work of release engineering was about last minute win9x work.
)

p.s. if you use Cyrillic to test unicode, I assume your codepage is not Russian (or another Cyrillic language?)  Try to print arab or something
« Last Edit: July 04, 2018, 12:07:43 pm by marcov »

palacs

  • New Member
  • *
  • Posts: 21
Re: Unicode characters on Win9x with TextOutW
« Reply #4 on: July 04, 2018, 01:36:31 pm »
Thanks for the clarification. I am still sorry that Windows 98 support has been abandoned in FPC and Lazarus, however I can understand your reasoning.

p.s. if you use Cyrillic to test unicode, I assume your codepage is not Russian (or another Cyrillic language?)  Try to print arab or something

I used cyrillic and greek characters in one single TextOutW call. All characters showed up correctly in Windows 98. My goal is to operate with this logic. As far as I know this would be even superior to MSLU which can only translate one unicode call to one ANSI call which would limit the output to one ANSI codepage. I don't think it would be able to handle unicode characters from more than one character sets (do what TextOutW does all at once). Correct me if I'm worng.

engkin

  • Hero Member
  • *****
  • Posts: 2513
Re: Unicode characters on Win9x with TextOutW
« Reply #5 on: July 04, 2018, 03:16:46 pm »
So, let's see TLabel. It comes from TCustomLabel that has a Paint function in customlabel.inc. It calls TCanvas.TextRect of the Graphics unit. TCanvas.TextRect creates a virtual rectangle for the text, does some coordinate calculations, then calls DrawText in winapi.inc. It calls WidgetSet.DrawText with the same parameters. Unfortunately, this is the point I gave up messing around in the abyss of LCL. Someone who is experienced enough, please tell me where should I modify the LCL in order to redirect all its wrapped text-drawing calls to TextOutW instead of other WINAPI functions which won't deal with unicode properly on Win9x.

You were almost there. Do a Search in Files for TextOut in your Lazarus\lcl\interfaces\win32\ folder. In my copy one result is in win32winapih.inc file:
Code: Pascal  [Select]
  1. function TextOut(DC: HDC; X, Y: Integer; Str: PChar; Count: Integer): Boolean; override;

its implementation in win32winapi.inc:
Code: Pascal  [Select]
  1. function TWin32WidgetSet.TextOut(DC: HDC; X, Y: Integer; Str: PChar; Count: Integer): Boolean;
  2. var
  3.   ws: widestring;
  4. begin
  5.   ws := UTF8ToUTF16(copy(str,1,Count));
  6.   Result := Boolean(Windows.TextOutW(DC, X, Y, PWideChar(ws), length(ws)));
  7. end;

Edit:
The same procedure in the Fixes_1_2 branch has:
Code: Pascal  [Select]
  1. function TWin32WidgetSet.TextOut(DC: HDC; X, Y: Integer; Str: PChar; Count: Integer): Boolean;
  2. {$ifdef WindowsUnicodeSupport}
  3. var
  4.   ws: widestring;
  5. {$endif}
  6. begin
  7. {$ifdef WindowsUnicodeSupport}
  8.   ws := UTF8ToUTF16(copy(str,1,Count));
  9.   Result := Boolean(Windows.TextOutW(DC, X, Y, PWideChar(ws), length(ws)));
  10. {$else}
  11.   Result := Boolean(Windows.TextOut(DC, X, Y, Str, Count));
  12. {$endif}
  13. end;

You might want to try recompile the whole thing with WindowsUnicodeSupport defined. I don't know if it work on Win98. Just give it a try.
« Last Edit: July 04, 2018, 03:26:18 pm by engkin »

Thaddy

  • Hero Member
  • *****
  • Posts: 8911
Re: Unicode characters on Win9x with TextOutW
« Reply #6 on: July 04, 2018, 03:41:51 pm »
The unicode support is from win95 onwards. From XP it is the default and since then Windows uses stubs/proxies for Ansi in most but not all cases to support Ansi.
- Up into Me,Ansi was default for the OS
- From XP (actually NT4, so even before that) Unicode is the default for the OS. NT4 was hardly used/installed by/for consumers.
Most people that want to use threading should learn to patch their jeans first: use a needle.

palacs

  • New Member
  • *
  • Posts: 21
Re: Unicode characters on Win9x with TextOutW
« Reply #7 on: July 04, 2018, 11:23:32 pm »
You might want to try recompile the whole thing with WindowsUnicodeSupport defined. I don't know if it work on Win98. Just give it a try.
It is defined by default and has always been. The problem is that the code part you copied doesn't get called. None of the branches of the ifdef or any part of that function. However, thanks for the hint, it helped me to go further. All TLabels will call DrawText, namely TWin32WidgetSet.DrawText, which is implemented in win32winapi.inc that you mentioned. I modified the function to overwrite its string to "test" then all my labels became like showing "test". However, TWin32WidgetSet.DrawText will call DrawTextA or DrawTextW of the Windows API directly. I tried to replace the WINAPI call DrawTextW (not supported by Win98) to ExtTextOutW (supported by Win98). It also supports clipping rectangle and flags that TextOut doesn't. What I couldn't figure out how to return the height of the text in logical units what its documentation says about the return value.

So I got stuck again. :(

Code: Pascal  [Select]
  1.   if UnicodeEnabledOS then
  2.   begin
  3.     // Whatever.. this is not going to be called under Win98
  4.   end
  5.   else
  6.   begin
  7.     W := UTF8ToUTF16(s);
  8.     Windows.ExtTextOutW(DC, Rect.Left, Rect.Top, Flags, @Rect, PWideChar(W), Length(W), Nil);
  9.     Result := Rect.Top - Rect.Bottom; // wrong
  10.   end;
  11.  

On the other hand it might be good news I also found an implementation for TWidgetSet.DrawText in intfbasewinapi.inc which doesn't get called but contains a full reimplementation of WINAPI's DrawTextA/DrawTextW and would be great if I could make TLabels and all other controls use it because it will call TextOut which I can replace to TextOutW in its ANSI block = means success. Somebody knows anything about this DrawText?
« Last Edit: July 04, 2018, 11:44:16 pm by palacs »

palacs

  • New Member
  • *
  • Posts: 21
Re: Unicode characters on Win9x with TextOutW
« Reply #8 on: July 05, 2018, 12:04:46 am »
I think I have figured out. The TWidgetSet.DrawText in intfbasewinapi.inc is there for platform-specific widget sets that don't implement this function because units like LCLIntf are still multi-platform and must support Delphi functions based on their Win32 API counterpart. So I removed DrawText from both win32winapi.inc and win32winapih.inc and voila, DrawText in intfbasewinapi.inc just got called. It called TextOut in win32winapi.inc that called TextOutW because WindowsUnicodeSupport was enabled. ;)

... and I FINALLY have unicode characters on all my labels in Windows 98. Special thanks goes to engkin who has put me in the right direction!

Next achievement would be labels of TTabSheets, TMemo and TEdit but that's another story for tomorrow. I need some sleep now. ::)
« Last Edit: July 05, 2018, 12:11:14 am by palacs »