Перейти к содержанию
Fire Monkey от А до Я
  • 0

[Windows] Сворачивание приложение


Menkos1

Вопрос

Форма на FireMonkey

студия: Delphi XE10.1

Суть проблемы:

Запускаю скомпилированное приложение, нажимаю на него на панели задач и ничего не происходит, а должен как и многие другие приложения и папка - сворачиваться и при следующем нажатие - разворачиваться.

Не могу понять, почему приложение не сворачивается.

 

 

Ссылка на комментарий

Рекомендуемые сообщения

  • 0
3 минуты назад, Вадим Смоленский сказал:

Есть ли способ проверить, какая редакция FMX.Platform.Win у меня подхватывается?

far, alt+f7, FMX.Platform.Win* по всем возможным локациям. Ещё можно грубую синтаксическую ошибку в pas файле сделать. Если компиллер ругнулся, файл тот. Если нет, то только п.1
 

Ссылка на комментарий
  • 0

Методом вставленной синтаксической ошибки установил, что подхватывается файл, положенный мной в папку проекта. То бишь, исправленный файл, содержащий секцию WM_SYSCOMMAND: begin ... end

Файлы FMX.Platform.Win.dcu из указанных папок удалил и теперь их нигде не наблюдаю.

Приложение, однако, функционирует по-старому. Похоже, что-то не так с рекомендованной вставкой.

Ссылка на комментарий
  • 0

Ха! Нет, не по-старому функционирует приложение! Добавился новый баг, еще хуже. При щелчке по системной кнопке "Свернуть" никакого сворачивания не происходит. Убрал вставленный фрагмент - всё восстановилось. Что-то в этом фрагменте точно напутано. Давайте взглянем на него еще разок:

WM_SYSCOMMAND:
  begin
   if wParam = SC_MINIMIZE then
     PlatformWin.MinimizeApp
   else if wParam = SC_RESTORE then
     PlatformWin.RestoreApp;
   DefWindowProc(HWND, uMsg, wParam, LPARAM);
   sleep(50); // у FMX какая-то беда с потоками, иногда при нажатии по иконуе приложения в TaskBar окно не сворачивается а снова активируется, sleep уменьшает количество таких глюков
   Winapi.Windows.SetActiveWindow(FormToHwnd(LForm)); // после разворота активирует окно - проверил в Berlin и Tokyo 10.2.2
  end;

Что тут не так?

Ссылка на комментарий
  • 0
В 11.03.2018 в 03:13, Вадим Смоленский сказал:

Ха! Нет, не по-старому функционирует приложение! Добавился новый баг, еще хуже. При щелчке по системной кнопке "Свернуть" никакого сворачивания не происходит. Убрал вставленный фрагмент - всё восстановилось. Что-то в этом фрагменте точно напутано. Давайте взглянем на него еще разок:


WM_SYSCOMMAND:
  begin
   if wParam = SC_MINIMIZE then
     PlatformWin.MinimizeApp
   else if wParam = SC_RESTORE then
     PlatformWin.RestoreApp;
   DefWindowProc(HWND, uMsg, wParam, LPARAM);
   sleep(50); // у FMX какая-то беда с потоками, иногда при нажатии по иконуе приложения в TaskBar окно не сворачивается а снова активируется, sleep уменьшает количество таких глюков
   Winapi.Windows.SetActiveWindow(FormToHwnd(LForm)); // после разворота активирует окно - проверил в Berlin и Tokyo 10.2.2
  end;

Что тут не так?

Да, все верно, там были ошибки, наверное уже не актуально, но выложу. Тот код у меня вырос до такого вот

 

        WM_SYSCOMMAND:
          begin
            case wParam of
              SC_MINIMIZE:begin
                PlatformWin.MinimizeApp;
                Result:=DefWindowProc(HWND, uMsg, wParam, LPARAM);
                FinalActionsOfPopups;
              end;
              SC_RESTORE:begin
                PlatformWin.RestoreApp;

                if Application.MainForm <> nil then
                  if OldWindowState = TWindowState.wsMaximized  then
                    Application.MainForm.WindowState := TWindowState.wsMaximized ;

                DefWindowProc(HWND, uMsg, wParam, LPARAM);
                Winapi.Windows.SetActiveWindow(FormToHwnd(LForm){WinAPI.Windows.FindWindow('TForm1','Form1')});
              end;
              SC_CLOSE:begin
                if CannotClose = True then
                  exit
                else
                  if Application.MainForm <> nil then
                  begin
                    for I := 0 to Screen.FormCount - 1 do
                   // if FormToHWND(Screen.Forms[I]) = hwnd then
                   // begin
                      Screen.Forms[I].Close;
  //                   Exit;
                   // end;




                    Application.MainForm.BorderStyle:=TFmxFormBorderStyle.None;
                    Application.MainForm.Height:=0;
                    Application.MainForm.Width:=0;
                    PlatformWin.RestoreApp;
                   // Application.MainForm.Activate;
                  end;
                Result := DefWindowProc(hwnd, uMsg, wParam, lParam);
              end;
              SC_MAXIMIZE:begin
                Winapi.Windows.ShowWindow(FormToHwnd(LForm), SW_MAXIMIZE);
                DefWindowProc(HWND, uMsg, wParam, LPARAM);
              end;
            end;
          end;

С такими изменениями вроде все работает корректно, еще раз просмотрел сейчас тот проект, вроде бы все адекватно отрабатывает, как и в VCL. 

Ссылка на комментарий
  • 0

Ах да CannotClose не нужен здесь, это костыль исходя из логики работы приложения, приложение не должно закрываться во время работы, на скорую руку делал, можно и красивее сделать было конечно

Ссылка на комментарий
  • 0
В 19.11.2018 в 12:40, sargon сказал:

С такими изменениями вроде все работает корректно

Воспроизвел изменения у себя - и увы! Не только сворачивание не стало работать правильно, но даже перетащить окно теперь не получается. Что-то с этим кодом всё равно не так...

Кстати, попробовал перехватить событие WM_SYSCOMMAND и обнаружил, что оно происходит только при щелчке по кнопке Minimize в шапке окна, а при щелчке по иконке в трее уже не происходит. Не то мы ловим.

Изменено пользователем Вадим Смоленский
Ссылка на комментарий
  • 0

Я в свое время тоже над этим бился...

Вот такая конструкция получилась (Delphi 10.2.3):

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Objects,
  FMX.Platform.Win,
  FMX.Platform,
  Winapi.Windows,
  Winapi.Messages,
  FMX.Memo;

type
  TForm1 = class(TForm)
  private
  type
    TShowAction = (saNone, saNormal, saMinimize, saMaximize);
  protected
    procedure CreateHandle; override;
  private
    AppIsActive : Boolean;
    FOldFMXWndProc : TFNWndProc;
    FNewFMXWndProc : Pointer;
    FShowAction: TShowAction;
    procedure FMXFormWndProc(var Msg: Winapi.Messages.TMessage);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

procedure TForm1.CreateHandle;
var
 H : HWND;
begin
 inherited CreateHandle;
 H := FormToHWND(Self);
 FOldFMXWndProc := TFNWndProc(GetWindowLong(H, GWL_WNDPROC));
 FNewFMXWndProc := MakeObjectInstance(FMXFormWndProc);
 SetWindowLong(H, GWL_WNDPROC, NativeInt(FNewFMXWndProc));
end ;

procedure TForm1.FMXFormWndProc(var Msg: Winapi.Messages.TMessage);
begin
  case Msg.Msg of

    WM_SHOWWINDOW :
    begin
      case TWMShowWindow(Msg).Status of
        SW_PARENTCLOSING:
          if FShowAction = saNone then
          begin
            if IsIconic(FormToHWND(Self)) then
              FShowAction := saMinimize
                else
              if IsZoomed(FormToHWND(Self)) then
                FShowAction := saMaximize
              else
                FShowAction := saNormal;

                TThread.CurrentThread.ForceQueue(nil,
                  procedure
                  begin
                   SendMessage(FormToHWND(Self),WM_SYSCOMMAND, SC_MINIMIZE,0);
                   WindowState := TWindowState.wsMinimized;
                  end);

          end;
        SW_PARENTOPENING:
          if FShowAction <> saNone then
          begin
              if FShowAction = saMaximize then
                WindowState := TWindowState.wsMaximized
               else
              if FShowAction = saNormal then
                 WindowState := TWindowState.wsNormal;
            FShowAction := saNone;
            exit;
          end;
      end;
    end;

    WM_NCACTIVATE :
    begin
      if (Msg.WParam = 0) then
        Msg.WParam := Byte(AppIsActive);
    end;
   end;

  Msg.Result := CallWindowProc(FOldFMXWndProc, FormToHWND(Self), Msg.Msg, Msg.WParam, Msg.LParam);

  case Msg.Msg of
    WM_ACTIVATEAPP :
    begin
     AppIsActive := Msg.WParam = 1 ;
    end ;
  end;

end;


end.

 

Ссылка на комментарий
  • 0
37 минут назад, mmover сказал:

Вот такая конструкция получилась

Да, я сейчас тоже попробовал сделать через перехват, только попроще. Работает. Вот как выглядит функция:

function NewWndProc(Wnd: HWND; Msg: UINT; WParam: WPARAM; LParam: LPARAM): LRESULT; stdcall;
begin
 if (Msg = WM_SHOWWINDOW) and (LParam = SW_PARENTCLOSING) then 
     begin
      SendMessage(FormToHWND(MainForm), WM_SYSCOMMAND, SC_MINIMIZE, 0);
      Application.ProcessMessages;
      MainForm.WindowState := TWindowState.wsMinimized;
     end
  else Result := CallWindowProc(OldWndProc, Wnd, Msg, WParam, LParam);
end;

ProcessMessages пришлось вставить из-за того, что без этого приложение перед сворачиванием на долю секунды становилось черным. Наверное, можно сделать изящнее - в вашем примере, как я понял, TThread помогает. Но все-таки оно работает, и это, безусловно, изящнее, чем курочить FMX.Platform.Win и таскать его туда-сюда.

Ссылка на комментарий
  • 0
10 часов назад, mmover сказал:

Вот такая конструкция получилась (Delphi 10.2.3):

Данный код не решает вопрос полностью, главное окно сворачивается на десктоп..

Вот полный лог сообщений, которые проходят по нажатию на иконку в таскбаре

00:31:19.313  WM_NCACTIVATE  0  0 
00:31:19.313  WM_ACTIVATEAPP: 0  10176 
00:31:19.401  SW_PARENTCLOSING  0  1 
00:31:19.404  WM_ACTIVATEAPP: 1  0  
00:31:19.410  WM_NCACTIVATE  0  8784630 
00:31:19.416  WM_NCACTIVATE  1  3213944 
00:31:19.422  WM_NCACTIVATE  2097152  8784630 
00:31:19.425  WM_ACTIVATEAPP: 0  5628  

/// нажали снова чтобы развернуть

00:31:22.349  WM_ACTIVATEAPP: 1  10176 
00:31:22.352  WM_NCACTIVATE  1  8784630 
00:31:22.383  WM_NCACTIVATE  0  8784630 
00:31:22.385  SW_PARENTOPENING  1  3 
00:31:22.388  WM_NCACTIVATE  1  8784630 
00:31:22.393  WM_NCACTIVATE  0  8784630 

 

Пока что я придумал только совсем дикое решение - повесить второй аналогичный хук на FMX.Platform.Win.ApplicationHWND с целью игнорировать второе "лишнее" WM_ACTIVATEAPP с wParam=1

 

P.S. Забавный парадокс, начал переходить на мультиплатформенный фреймворк - пришлось плотнее углубиться в изучение WinAPI:))) (эта тема плюс

 

Изменено пользователем Nick Peterson
Ссылка на комментарий
  • 0

Немножко улучшил свой вариант. Теперь вообще как часы всё заработало.

var TheFormIsMinimized: Boolean = False;
    TheFormWasMaximized: Boolean = False;

function NewWndProc(Wnd: HWND; Msg: UINT; WParam: WPARAM; LParam: LPARAM): LRESULT; stdcall;
begin
 if (Msg = WM_SHOWWINDOW) and (LParam = SW_PARENTCLOSING) and (not TheFormIsMinimized) then
     begin
      TheFormIsMinimized := True;
      TheFormWasMaximized := (MainForm.WindowState=TWindowState.wsMaximized);
      SendMessage(FormToHWND(MainForm), WM_SYSCOMMAND, SC_MINIMIZE, 0);
      MainFormp.WindowState := TWindowState.wsMinimized;
     end else
 if (Msg = WM_SHOWWINDOW) and (LParam = SW_PARENTOPENING) and (TheFormIsMinimized) then 
     begin
      TheFormIsMinimized := False;
      SendMessage(FormToHWND(MainForm), WM_SYSCOMMAND, SC_RESTORE, 0);
      if TheFormWasMaximized
         then MainForm.WindowState := TWindowState.wsMaximized
         else MainForm.WindowState := TWindowState.wsNormal;
     end
  else Result:=CallWindowProc(OldWndProc, Wnd, Msg, WParam, LParam);
end;

Единственный недостаток: при восстановлении из wsMinimized в wsMaximized на долю секунды окно фиксируется как wsNormal. Но это, в общем-то, не страшно.

Ссылка на комментарий
  • 0

В Рио ктото адаптировал? Там весь модуль FMX.Platform.Win.pas переписан. Но ошибка как была так и осталась.

Проблема возникает не с главной формой, а с модальным окном. 

При нажатии на иконку в таскбаре событие 

WM_SHOWWINDOW, WM_SYSCOMMAND  

не вызывается. Что же перехватить блин?)))

Изменено пользователем SVTX
Ссылка на комментарий

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...