Превращаем главное скрытое окно программы в действительно главное окно программы

Источник: delphikingdom
Дмитрий Ларионов

Автор: Дмитрий Ларионов

Ни для кого думаю не секрет, что главным окном приложения, при подключении модуля Forms, является не ваша главная форма проекта, а невидимое окно создаваемое в TApplication (далее AppОкно). Если в ранних версиях Windows его почти не заметно, то в Windows Vista проявляется "левость" этого окна: когда вы сворачиваете программу, то в TaskBar'е, во всплывающем Preview, рисуется белое пятно с иконкой вашей программы, а не уменьшенная копия главного окна. Можно было бы сказать "спасибо, что не всегда" (а, кстати говоря, могло бы и всегда рисоваться белое пятно, и только благодаря Windows этого не происходит. Windows видит, что главное окно нулевых размеров и для Preview берёт следующее видимое окно.), но мне это постоянно не давало покоя. Оно и раньше мне не нравилось (я почти, процентов на 95, уверен, что при желании можно было бы обойтись без него), но все попытки избавиться или как-то обойти его терпели неудачу, а раз окно есть и оно, ни много ни мало, главное, windows справедливо рисует пустоту...

Я не знаю исправлено ли это в новых версиях Delphi, а для Delphi <= 2006 главным и, кажется, единственным известным способом избавления от этого "позорного пятна" является сокрытие главного окна проекта, и перенос всего функционала на другую форму и присваивание этой форме стиля WS_EX_APPWINDOW.

//DPR
begin
  Application.Initialize;
  Windows.SetWindowLong(Application.Handle, GWL_EXSTYLE,
      Windows.GetWindowLong(Application.Handle, GWL_EXSTYLE) or
      WS_EX_TOOLWINDOW and not WS_EX_APPWINDOW); //Запрещаем AppОкну отображаться в TaskBar'е

  Application.CreateForm(TForm1, Form1); //главная форма проекта
  Application.CreateForm(TForm2, Form2); //её заместитель
  Application.ShowMainForm := False; //<--- !
  Application.Run;
end.

//Unit2
type
  TForm2 = class(TForm)
  private
  protected
    procedure CreateParams(var Params: TCreateParams); override;
  public

  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

{ TForm2 }

procedure TForm2.CreateParams(var Params: TCreateParams);

begin
  inherited;
  Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW and not WS_EX_TOOLWINDOW;
end;

К сожалению это не решение проблемы, а лишь заплатка. Так, например, в программе, где не модальных форм больше чем одна, при переключении на другое окно, окно-заместитель-главного становится не активным, а вместе с ним и кнопка в TaskBare'е теряет "фокус". Назначать всем окнам программы стиль WS_EX_APPWINDOW тоже не выход.

Попытки манипулирования AppОкном всё же привели к несколько неожиданному, но желаемому результату. Я нашёл как справиться с этой занозой и при этом не придется ничего менять в программе (ну почти ничего).

Я сделал AppОкно ...барабанная дробь... "главным окном программы". Т.е. буквально. AppОкно теперь не нулевых размеров, а видно на экране и оно не пустое, а с функционалом главной формы проекта (точнее, с внедрённой в неё главной формы проекта). Для этого требуется совершить несколько простых действий.

  1. Подключить модуль AppEx.pas к проекту.
  2. В TForm1 (будем считать её гравной формой проекта) добавьте
  3. type
      TForm1 = class(TForm)
               //...
      protected //<------
        procedure CreateParams(var Params: TCreateParams); override; //<------
    
      end;
    
    implementation
    
    {$R *.dfm}
    
    procedure TForm1.CreateParams(var Params: TCreateParams);
    begin
    
      inherited;
      Params.Style := WS_CHILD or WS_CLIPCHILDREN or WS_CLIPSIBLINGS or WS_VISIBLE or WS_TABSTOP;
      Params.WndParent := Application.Handle;
    end;
    
    

  4. Переключитесь в DPR и добавьте код:
  5. begin
      Application.Initialize;
      Application.CreateForm(TForm1, Form1); //главная форма проекта
      Application.CreateForm(TForm2, Form2); //предположим, что у вас несколько форм в проекте
    
      ApplicationInitialize; //<-----
      Application.Run;
      ApplicationFinalize; //<-----
    end.
    

  6. Во всех остальных не модальных формах проекта, если таковые имеются, надо добавить:
  7. type
      TForm2 = class(TForm)
               //...
      protected //<------
        procedure CreateParams(var Params: TCreateParams); override; //<-------
    
      end;
    
    implementation
    
    {$R *.dfm}
    
    uses AppEx;  //<------
    
    procedure TForm2.CreateParams(var Params: TCreateParams);
    
    begin
      inherited;
      Params.WndParent := AppWnd; //<------
    end;
    

А лучше всего унаследовать все не модальные окна от базовой, а уже в базовой поправить CreateParams как в пункте 4.


Страница сайта http://185.71.96.61
Оригинал находится по адресу http://185.71.96.61/home.asp?artId=21607