Site icon Embarcadero RAD Studio, Delphi, & C++Builder Blogs

Как ускорить приложения удаленного рабочего стола

remote desktop faster

Одним из обновлений функции RAD Studio 10.4.2, основанным на анализе, показывающем рост числа разработчиков, использующих удаленный рабочий стол для разработки во время Covid, стало ускорение рендеринга IDE через удаленный рабочий стол.

Основными проблемами были зависание IDE в некоторых ситуациях (например, при подключении или отключении удаленного рабочего стола), мерцание и несколько AV.

Пункты QP, рассмотренные для 10.4.2, включают:

Кроме того, был ряд внутренних отчетов.

Хотя у меня нет образца проекта, которым можно поделиться, у меня есть разрешение поделиться некоторыми заметками, которые команда разработчиков Embarcadero предоставила на основе своего опыта, и я надеюсь, что это будет полезно и другим разработчикам.

Основная причина всех этих проблем заключается в том, что любое изменение сеанса RDP (блокировка, разблокировка, подключение, отключение) вызывает изменение общесистемных настроек (WM_SETTINGCHANGE), вызывая каскад сообщений, который приводит к множеству перерисовок в среде IDE. Это было причиной некоторых антивирусных программ, поскольку между каскадными сообщениями, отправленными ОС, оно включало сообщение WM_THEMECHANGED, которое запускало воссоздание дескриптора для некоторых элементов управления. Это повлияло на разработчиков VCL / FMX, когда они были оставлены открытыми и сеанс был повторно подключен через RDP.

WTS API предоставляет возможность получать уведомление изменения RDP сессии (WM_WTSSESSION_CHANGE). Управление этим позволяет IDE получать уведомления, когда сеанс заблокирован, разблокирован, подключен, отключен, и отсюда мы можем выбрать, как обрабатывается WM_SETTINGCHANGE, и избежать проблем с мерцанием / перерисовкой.

Одно замечание от команды R&D заключалось в том, что использование стилей VCL в службах терминалов с большей вероятностью заставит приложение видеть мерцание при нормальных обстоятельствах.

Мы надеемся, что этот скелетный образец кода (непроверенный) предоставит указатели в правильном направлении для всех, кто хочет добавить аналогичную поддержку в свои приложения.

type
  TFormMain = class(TForm)
    TimerEnableMetricSettings : TTimer;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure TimerEnableMetricSettingsOnTimer(Sender: TObject);
  private
    FMethodWnd: HWND;
    procedure WTS_SessionWndProc(var Message: TMessage);
    procedure DoHandleRDPLock;
    procedure DoHandleRDPUnLock;
  end;

var
  FormMain: TFormMain;

implementation
{$R *.dfm}

procedure TFormMain.DoHandleRDPLock;
begin
  // Prevent the VCL App reacting to WM_SETTINGCHANGE when a rdp session is locked/disconnected.
  // Stop the timer if it's already running
  if TimerEnableMetricSettings.Enabled then
    TimerEnableMetricSettings.Enabled := False;
  Application.UpdateMetricSettings := False;
end;

procedure TFormMain.DoHandleRDPUnLock;
begin
  // Stop the timer if it's already running
  if TimerEnableMetricSettings.Enabled then
    TimerEnableMetricSettings.Enabled := False;
  // Re-start the timer.
  TimerEnableMetricSettings.Enabled := True;
end;

procedure TFormMain.FormCreate(Sender: TObject);
begin
  TimerEnableMetricSettings.Interval := 30000;
  TimerEnableMetricSettings.Enabled := False;
  // This hooks to the method WTS_SessionWndProc below to control the Lock
  FMethodWnd := AllocateHWnd(WTS_SessionWndProc); 
  WTSRegisterSessionNotification(FMethodWnd, NOTIFY_FOR_THIS_SESSION);
end;
   
procedure TFormMain.FormDestroy(Sender: TObject);
begin
  if FMethodWnd <> 0 then
  begin
    WTSUnRegisterSessionNotification(FMethodWnd);
    DeallocateHWnd(FMethodWnd);
  end;
end;

procedure TFormMain.WTS_SessionWndProc(var Message: TMessage);
begin
  if Message.Msg = WM_WTSSESSION_CHANGE then
  begin
    case Message.wParam of
      WTS_SESSION_LOCK,
      WTS_REMOTE_DISCONNECT:  DoHandleRDPLock;
      WTS_REMOTE_CONNECT,
      WTS_SESSION_UNLOCK:  DoHandleRDPUnLock;
    end;
  end;
  Message.Result := DefWindowProc(FMethodWnd, Message.Msg, Message.WParam, Message.LParam);
end;

procedure TFormMain.TimerEnableMetricSettingsOnTimer(Sender : TObject);
begin
  // stop the timer
  TimerEnableMetricSettings.Enabled := False;
  // it is recommended to wait a few seconds before this is run
  // hence setting the timer interval to 30000 in FormCreate 
  Application.UpdateMetricSettings := True;  
end;

end.
Exit mobile version