TNTForms and Cooltrayicon

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!