Recent

Author Topic: Wrong icon for new window when mainform is invisible  (Read 16690 times)

GADZombie

  • New Member
  • *
  • Posts: 46
  • 8bitrlz
    • Zombie Mastah
Re: Wrong icon for new window when mainform is invisible
« Reply #15 on: January 30, 2014, 10:49:52 am »
Well, I think this issue can be closed, but I've learned something new.
I tried the same in Delphi 2010 today and it looks like there is the same behaviour. Everything works fine until the window has no border. It always receive default application icon and has no it's own icon. Maybe it's because window has no border, so it has no icon, and default application icon is assigned to taskbar button, because borderless window cannot have an icon.
But it's bad. I wanted to do it and I thought it will be easy :). It is not.
I have an idea, but I must try it. Maybe I will open main application window in minimised state, when I need to create additional borderless window. It's not the best solution, but I have no better idea now.

reinerr

  • New Member
  • *
  • Posts: 37
Re: Wrong icon for new window when mainform is invisible
« Reply #16 on: February 06, 2014, 06:22:30 am »
I had a bit of a play (Windows 7 64-bit).

If the secondary form is border-less, as in your example, and the main window is hidden Windows never asks for ICON_BIG (with WM_GETICON). If the main window is visible or the secondary form has a border then this message is sent.

So I'm not sure where the problem is nor how to resolve it.

EDIT: I just tried with Delphi 7 and same result. If the main form is visible or the app is in the task bar then the icon changes, if the main form is hidden and there is no app icon in the taskbar then the icon is not updated. Actually hiding the app button from the taskbar required a bit of research! So this now definitely seems to be a "feature" of Windows.
« Last Edit: February 06, 2014, 06:51:27 am by reinerr »

GADZombie

  • New Member
  • *
  • Posts: 46
  • 8bitrlz
    • Zombie Mastah
Re: Wrong icon for new window when mainform is invisible
« Reply #17 on: February 06, 2014, 09:09:11 am »
Thanks for you reply.

I don't think this is Windows feature. I made this in Delphi 2010, but still I'm not sure it will work in Lazarus. I'll try it later.
Look at attached example.
The most important part is:
Override the CreateParams procedure in borderless form:
Code: [Select]
procedure TBorderlessForm.CreateParams(var Params: TCreateParams);
begin
  inherited;
  Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
  Params.WndParent := GetDesktopWindow;  //without this line assigned icon will not work
end;
I must assign WndParent to GetDesktopWindow result.
I haven't find this function in Lazarus, but it's from user32.dll:
Code: [Select]
function GetDesktopWindow; external user32 name 'GetDesktopWindow';

The second part is hiding main form with this:
Code: [Select]
procedure TMainForm.btnHideClick(Sender: TObject);
begin
  self.hide;
  Application.ShowMainForm := False;
  ShowWindow(Application.Handle, SW_HIDE);    //mainform button is hidden
//  ShowWindow(Application.MainForm.Handle, SW_HIDE);   //mainform button is not hidden
end;

And the worst is that in Lazarus there is no Application.Handle! I don't know what is this, but in Delphi assignment to FHandle looks like this:

Code: [Select]
[UIPermission(SecurityAction.LinkDemand, Window=UIPermissionWindow.AllWindows)]
procedure TApplication.CreateHandle;
var
  LHandle: HWND;
  SysMenu: HMenu;
{$IF DEFINED(CLR)}
  TempClass: TWndClassInfo;
  WindowClass: TWndClass;
{$ELSE}
  TempClass: TWndClass;
{$IFEND}
begin
{$IF DEFINED(CLR)}
  if not FHandleCreated and not IsConsole then
  begin
    if not Assigned(FResources) then
      FResources := TApplicationResources.Create;
    FResources.FObjectInstance := MakeObjectInstance(WndProc);
    WindowClass.lpszMenuName := '';
    WindowClass.lpszClassName := 'TApplication';
{$ELSE}
{$IFDEF MSWINDOWS}
  if not FHandleCreated and not IsConsole then
{$ENDIF}
{$IFDEF LINUX}
  if not FHandleCreated then
{$ENDIF}
  begin
    FObjectInstance := MakeObjectInstance(WndProc);
{$IFEND}
    WindowClass.lpfnWndProc := @DefWindowProc;
    if not GetClassInfo(HInstance, WindowClass.lpszClassName, TempClass) then
    begin
      WindowClass.hInstance := HInstance;
      if Windows.RegisterClass(WindowClass) = 0 then
        raise EOutOfResources.Create(SWindowClass);
    end;
    LHandle := CreateWindowEx(WS_EX_TOOLWINDOW, WindowClass.lpszClassName, {$IFNDEF CLR}PChar{$ENDIF}(FTitle),
      WS_POPUP or WS_CAPTION or WS_CLIPSIBLINGS or WS_SYSMENU
      or WS_MINIMIZEBOX,
      GetSystemMetrics(SM_CXSCREEN) div 2,
      GetSystemMetrics(SM_CYSCREEN) div 2,
      0, 0, 0, 0, HInstance, nil);
{$IF DEFINED(CLR)}
    FResources.FHandle := LHandle;
{$ELSE}
    FHandle := LHandle; //<----------- HERE
{$IFEND}
    FHandleCreated := True;
{$IF DEFINED(CLR)}
    SetWindowLong(Handle, GWL_WNDPROC, @FResources.FObjectInstance);
{$ELSE}
    SetWindowLong(FHandle, GWL_WNDPROC, LPARAM(FObjectInstance));
{$IFEND}
    if NewStyleControls then
    begin
      SendMessage(Handle, WM_SETICON, ICON_BIG, LPARAM(GetIconHandle));
      SetClassLong(Handle, GCL_HICON, LPARAM(GetIconHandle));
    end;
    SysMenu := GetSystemMenu(Handle, False);
    DeleteMenu(SysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
    DeleteMenu(SysMenu, SC_SIZE, MF_BYCOMMAND);
    if NewStyleControls then DeleteMenu(SysMenu, SC_MOVE, MF_BYCOMMAND);
  end;
end;

When I use Application.Mainform.Handle, it works weird, because if another than mainform window is visible, the mainform button will not disappear from taskbar. When there is no other forms visible, mainform button will hide. So this is not what I want.
Using this wih Application.Handle works fine in Delphi.

GADZombie

  • New Member
  • *
  • Posts: 46
  • 8bitrlz
    • Zombie Mastah
Re: Wrong icon for new window when mainform is invisible
« Reply #18 on: February 06, 2014, 08:13:21 pm »
It worked in Lazarus!
I had to add this one procedure:

Code: [Select]
procedure TBorderlessForm.CreateParams(var Params: TCreateParams);
begin
  inherited;
  Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
  Params.WndParent := GetDesktopWindow;
end;

And it works as I want. So the WndParent must be set to DesktopWindow handle taken from GetDesktopWindow function. I was wrong, this function is in Lazarus also, but in Windows unit.

So, the problem is solved :) Great! Thank you all!
« Last Edit: February 06, 2014, 09:32:36 pm by GADZombie »

 

TinyPortal © 2005-2018