リモート デスクトップ サービス経由で実行する必要がある Delphi プログラムがあります。正常に動作しなくなるのに注意すべきことは何ですか?
6 に答える
アンドレアスは、ダブルバッファリングのピンポイントで正しいです。これは、私が認識している考慮すべき最も重要な側面です。
控えめな反論として、私は一般的にダブルバッファリングは好きではありません。多くのコンポーネントは成功しません。Windows Basic のすぐ下に描画されない VCL ドロップダウン リスト ボックスについて考えています。他にもあります!
しかし、一部のコントロールでは、ちらつきを避けるためにダブル バッファリングが本当に必要です。ユーザーがローカルに接続している場合はダブル バッファリングの利点が必要ですが、リモートにいる場合はネットワーク帯域幅でユーザーに負担をかけたくありません。
だから、これが私がすることです:
procedure WMWTSSessionChange(var Message: TMessage); message WM_WTSSESSION_CHANGE;
procedure TBaseForm.WMWTSSessionChange(var Message: TMessage);
begin
case Message.WParam of
WTS_CONSOLE_DISCONNECT,WTS_REMOTE_DISCONNECT,
WTS_SESSION_LOCK,WTS_SESSION_LOGOFF:
SessionDisconnected;
WTS_CONSOLE_CONNECT,WTS_REMOTE_CONNECT,
WTS_SESSION_UNLOCK,WTS_SESSION_LOGON:
SessionConnected;
end;
inherited;
end;
function WTSRegisterSessionNotification(hWnd: HWND; dwFlags: DWORD): BOOL; stdcall; external 'Wtsapi32.dll';
function WTSUnRegisterSessionNotification(hWnd: HWND): BOOL; stdcall; external 'Wtsapi32.dll';
const
NOTIFY_FOR_THIS_SESSION = 0;
NOTIFY_FOR_ALL_SESSIONS = 1;
procedure TBaseForm.CreateWnd;
begin
inherited;
WTSRegisterSessionNotification(WindowHandle, NOTIFY_FOR_THIS_SESSION);
end;
procedure TBaseForm.DestroyWnd;
begin
WTSUnRegisterSessionNotification(WindowHandle);
inherited;
end;
私のアプリのすべてのフォームは、この動作から派生しTBaseForm
ているため、この動作を継承しています。SessionConnected
およびSessionDisconnected
メソッドはvirtual
、個々のフォームが特定のアクションを実行できるようにするためのものです。
特に、私のすべてのフォームは次のように呼び出しますUpdateDoubleBuffered
:
function InRemoteSession: Boolean;
begin
Result := Windows.GetSystemMetrics(SM_REMOTESESSION)<>0;
end;
class procedure TBaseForm.UpdateDoubleBuffered(Control: TWinControl);
var
DoubleBuffered: Boolean;
begin
if InRemoteSession then begin
//see The Old New Thing, Taxes: Remote Desktop Connection and painting
DoubleBuffered := False;
end else begin
DoubleBuffered := (Control is TCustomListView)
or (Control is TCustomStatusBar);
//TCustomListView flickers when updating without double buffering
//TCustomStatusBar has drawing infidelities without double buffering in my app
end;
Control.DoubleBuffered := DoubleBuffered;
end;
procedure TBaseForm.UpdateDoubleBuffered;
var
Control: TControl;
begin
for Control in ControlEnumerator(TWinControl) do begin
UpdateDoubleBuffered(TWinControl(Control));
end;
end;
ControlEnumerator
コンポーネントの子を処理する列挙子です。
Old New Thing の参照は、このコードの多くのインスピレーションとなったTaxes: Remote Desktop Connection and paintingというタイトルの記事です。
リモート デスクトップに関連する問題は他にもあると思いますが、ダブル バッファリングは確かに重要な問題の 1 つです。
ダブルバッファリングもその 1 つです。
一般に、ダブルバッファリングは素晴らしいことであり、私は常にそれを使用しています。たとえば、私のコンポーネント(1)、(2)、および(3)を参照してください。それらはすべてダブルバッファリングされているため、ちらつきが完全にありません (実装も簡単です)。
これが数百または数千のユーザーによって実行される企業全体または Web 配信のアプリである場合は、色深度、グラデーション、および軽薄なアニメーションに特に注意してください。特にあのラスト。16x16 の回転する「同期」アイコンは帯域幅をあまり消費しませんが、大きなものは大量のトラフィックを生成する可能性があります。色レベルが下がると、グラデーションは見栄えが悪く、うまく圧縮されません。ネットワーク/システム管理者がネットワークからさらに絞り出す必要がある場合、色レベルは下がります。コントロールできない場合があります。これらの懸念は、通常、完全なデスクトップなしで実行される Citrix アプリにも当てはまります。これに伴うもう 1 つの考慮事項は、システム トレイの通知領域がユーザーに表示されないことです。
アルファ透過形式は、IME で十分にサポートされていません (バージョンに応じて、クライアントまたはサーバーのいずれかによって)。
また、色についても心配する必要があります。ほとんどのリモート デスクトップは 16 ビット色、または 256 色で動作します。クリーンでモダンな UI を使用している場合は、「醜い」モードに落として、すべてが保証されるようにする必要がある場合があります。読み取り可能。
同じように、アンチエイリアス テキストに注意してください。これは、最新の UI では必須ですが、ローカラー RDP では文字がぼやけて判読不能になる可能性があります。
通知バブルやその他のシェルベースの効果には他の問題がある可能性があるため、Windows API 機能に依存するのではなく、通常の形式で自分で処理することをお勧めします。
グラフィカルに言えば、ダブル バッファリングは両刃の剣になる可能性があります。場合によっては (控えめなグラフィックスの場合)、オフにすることが有益な場合もありますが、より高度なレンダリング (グラデーション、透明なビットマップ、スケーリングされたビットマップ、ファンシー フォント) がある場合は、 、アンチエイリアシングされた線など) ちらつきのあるインタラクティブな描画よりもわずかな遅れが改善されるため、ダブルバッファリングを使用すると、見栄えと速度が向上します。
また、一部のビットマップは他のビットマップよりも高速に処理できます。RDP で使用される通常の高速圧縮では、水平方向のグラデーションよりも垂直方向のグラデーションが優先されます。
アプリケーションを通常のユーザー アカウントで実行する必要がない場合、別の問題はファイル権限にあります。また、特別なフォルダー (temp など) とレジストリ キーには、異なる (動的な) 場所と制限を設定できます。ただし、制限付きのユーザー アカウントで既にアプリケーションを実行している場合は、すべてがカバーされているはずです。
Citrix では、プリンターに問題がありました。クライアントが自分のマシンで定義したプリンターを接続で使用する場合もあれば、プリンターが他のユーザーのセッションからのものである場合もあれば、ユーザーがアクセスできない完全に別の場所にあるデフォルトのプリンターを使用する場合もあります。
ちらつきが多すぎて、リモートデスクトップで使用できないという多くの問題がありました。これは、キャプションやステータス パネルなどを毎秒何度も更新していたためです。キャプションが実際に変更されたかどうかを確認するために、すべての update-UI コードを変更しました。
if Str<>WeirdControl.Property1 then
WeirdControl.Property1 := Str; // minimize number of invalidates in case the control doesn't have it.
他の回答で言及されている他のこととともに、これにより、リモートデスクトップの状況でアプリケーションが再び使用できるようになりました.