I'm in the process of adding Unicode support to a Delphi 7 application with the help of TNT Controls. It works great so far.
But now I have run into a major problem.
If I descent my mainform from a TTntForm
TForm1 = class(TTntForm{TNT-ALLOW TTntForm})
I can assign a widestring to Form1.Caption and the Caption will display Unicode strings.
Unfornunately a well known component that is no longer supported called TCoolTrayIcon breaks this support.
So I'm looking at the code of TNTForms.pas and CoolTrayIcon.pas in order to find the problem.
It is related to the hooking of WndProc of the Mainform. It is done by
constructor TTntApplication.Create(AOwner: TComponent);
...
Application.HookMainWindow(WndProc);
But also by Cooltrayicon.pas
procedure TCoolTrayIcon.HookForm;
...
SetWindowLong((Owner as TWinControl).Handle, GWL_WNDPROC, LongInt(NewWndProc));
If I comment out the CoolTrayIcon hook, Unicode window caption support is back, but some events of Cooltrayicon are lost.
I've looked at the CooltrayIcon Hookingproc and nothing there seems to be related to unicode. Also the original procedure is called in the end, so the chain is not broken.
procedure TCoolTrayIcon.HookFormProc(var Msg: TMessage);
function DoMinimizeEvents: Boolean;
begin
Result := False;
if FMinimizeToTray then
if Assigned(FOnMinimizeToTray) then
begin
FOnMinimizeToTray(Self);
DoMinimizeToTray;
Msg.Result := 1;
Result := True;
end;
end;
begin
case Msg.Msg of
WM_SHOWWINDOW: begin
if (Msg.wParam = 1) and (Msg.lParam = 0) then
begin
// Show the taskbar icon (Windows may have shown it already)
// ShowWindow(Application.Handle, SW_RESTORE);
// Bring the taskbar icon and the main form to the foreground
SetForegroundWindow(Application.Handle);
SetForegroundWindow((Owner as TWinControl).Handle);
end
else if (Msg.wParam = 0) and (Msg.lParam = SW_PARENTCLOSING) then
begin
// Application is minimizing (or closing), handle MinimizeToTray
if not Application.Terminated then
if DoMinimizeEvents then
Exit; // Don't pass the message on
end;
end;
WM_SYSCOMMAND:
// Handle MinimizeToTray by capturing minimize event of form
if Msg.wParam = SC_MINIMIZE then
if DoMinimizeEvents then
Exit; // Don't pass the message on
{
This condition was intended to solve the "Windows can't shut down" issue.
Unfortunately, setting FormStyle or BorderStyle recreates the form, which
means it receives a WM_DESTROY and WM_NCDESTROY message. Since these are
not passed on the form simply disappears when setting either property.
Anyway, if these messages need to be handled (?) they should probably
be handled at application level, rather than form level.
WM_DESTROY, WM_NCDESTROY: begin
Msg.Result := 1;
Exit;
end;
}
end;
{
case Msg.Msg of
WM_QUERYENDSESSION: begin
Msg.Result := 1;
end;
else
}
// Pass the message on
Msg.Result := CallWindowProc(OldWndProc, (Owner as TWinControl).Handle,
Msg.Msg, Msg.wParam, Msg.lParam);
{
end;
}
end;
I would be very glad for any hints how to fix this issue!
Since I don't have forum rights to edit my posts, here is some additional info as a new post.
If I reduce the CoolTrayIcon hook function to barebone, so it does absolutely nothing but passing the message to the original procedure
procedure TCoolTrayIcon.HookFormProc(var Msg: TMessage);
begin
Msg.Result := CallWindowProc(OldWndProc, (Owner as TWinControl).Handle,
Msg.Msg, Msg.wParam, Msg.lParam);
end;
It still breaks TNTForms unicode caption support.
Although I'm not familiar with the CoolTrayIcon code here and cannot judge whether there are other issues in mixing a non-unicode TCoolTrayIcon with a unicode form, I believe you need at least to call CallWindowProcW() to invoke the unicode variant instead of the standard ANSI variant that is called with Delphi 7
Thanks Bruno! It was something similar.
We fixed the problem about 30 minutes ago. Here is the new CoolTrayIcon code that doesn't break TNTForms Unicode support.
GetWindowLong and SetWindowLong must be replaced with the PtrW versions:
procedure TCoolTrayIcon.HookForm;
begin
if (Owner as TWinControl) <> nil then
begin
// Hook the parent window
OldWndProc := Pointer(GetWindowLongPtrW((Owner as TWinControl).Handle, GWL_WNDPROC));
//OldWndProc := Pointer(GetWindowLong((Owner as TWinControl).Handle, GWL_WNDPROC));
{$IFDEF DELPHI_6_UP}
NewWndProc := Classes.MakeObjectInstance(HookFormProc);
{$ELSE}
NewWndProc := MakeObjectInstance(HookFormProc);
{$ENDIF}
SetWindowLongPtrW((Owner as TWinControl).Handle, GWL_WNDPROC, LongInt(NewWndProc));
//SetWindowLong((Owner as TWinControl).Handle, GWL_WNDPROC, LongInt(NewWndProc));
end;
end;
Thanks for sharing!