During testing, I found out that long Windows native controls - like non-balloon tooltip - will get truncated for most Delphi versions when VCL styling is enabled.
The fix is at https://gitlab.com/wiert.me/public/delphi/DelphiVclStylesAndHintText
The Delphi versions affected appear to be at least Delphi XE6 through XE8, which started to incorporate more stuff from https://github.com/RRUZ/vcl-styles-utils which has a different implementation of TSysControl.GetText
than the VCL one and limits to 1K characters.
Basically it is https://github.com/RRUZ/vcl-styles-utils/blame/master/Common/Vcl.Styles.Utils.SysStyleHook.pas#L454
function TSysControl.GetText: String;
var
Buffer: array [0 .. 1023] of Char;
begin
SetString(Result, Buffer, Winapi.Windows.GetWindowText(Handle, Buffer, Length(Buffer)));
end;
versus the VCL doing a combination of
function TSysControl.GetText: String;
begin
Result := GetSysWindowText(Handle);
end;
and
function GetSysWindowText(Window: HWND): string;
var
Text: array[0..256] of Char;
begin
SetString(Result, Text, Winapi.Windows.GetWindowText(Window, Text, Length(Text)));
end;
The last function should be something like either of the ones below.
// Two ways of doing this: using GetWindowText or by sending a WM_GETTEXT message
// https://blogs.msdn.microsoft.com/oldnewthing/20030821-00/?p=42833 explains the difference and favours WM_GETTEXT, but your mileage might vary
// - GetWindowText: https://msdn.microsoft.com/en-us/library/windows/desktop/ms633520.aspx
// - WM_GETTEXT: https://msdn.microsoft.com/en-us/library/windows/desktop/ms632627.aspx
function GetSysWindowText_GetWindowText(Window: HWND): string;
var
RequiredTextLength: Integer;
ObtainedTextLength: Integer;
begin
RequiredTextLength := SendMessage(Window, WM_GETTEXTLENGTH, 0, 0);
SetString(Result, PChar(nil), RequiredTextLength);
if RequiredTextLength <> 0 then
begin
ObtainedTextLength := Winapi.Windows.GetWindowText(Window, PChar(Result), RequiredTextLength);
if ObtainedTextLength < RequiredTextLength then
SetLength(Result, ObtainedTextLength);
end;
end;
function GetSysWindowText_WMGetText(Window: HWND): string;
var
RequiredTextLength: Integer;
ObtainedTextLength: Integer;
begin
RequiredTextLength := SendMessage(Window, WM_GETTEXTLENGTH, 0, 0);
SetString(Result, PChar(nil), RequiredTextLength);
if RequiredTextLength <> 0 then
begin
ObtainedTextLength := SendMessage(Window, WM_GETTEXT, WParam(RequiredTextLength + 1), LParam(PChar(Result)));
if ObtainedTextLength < RequiredTextLength then
SetLength(Result, ObtainedTextLength);
end;
end;
The fundament of the patch code in the project is by Stefan Glienke as it builds on the patch mechanism used in various Spring4D patches.
I have done minor alterations, including a dependency on JEDI.inc from the JEDI repository to patch only for affected Delphi versions.
The patch will not be applied when:
- you define
Skip_Patch_Vcl_Themes_GetSysWindowText
at your project level. - Delphi < XE6 or Delphi > 10.1 Berlin
In order to reproduce the issue, I have also adopted ComponentBaloonHintU from https://stackoverflow.com/questions/26247528/displaying-x-icon-in-tballoonhint
You can see the behaviour by defining Skip_Patch_Vcl_Themes_GetSysWindowText
.