• 0
Menkos1

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

Вопросы

Форма на FireMonkey

студия: Delphi XE10.1

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

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

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

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

35 ответов на этот вопрос

  • 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 пользователей онлайн

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