Modale Fenster in den Vordergrund holen
Möglicherweise kennen Sie das Phänomen: ein modales Fenster (z.B. ein Dialog) gerät völlig unmotiviert in den Hintergrund.
Evtl. bekommen Sie es mit ALT + TAB wieder nach vorn, aber auch das klappt nicht immer. Um dies zu beheben, können
Sie die Klasse aus der nachfolgenden Unit benutzen.
(**************** ModalFix - eine Hilfsklasse für modale Fenster **************) (* *) (* Copyright(c) 2011 Detlef Heibing *) (* *) (******************************************************************************) unit uModalFix; interface uses Windows; type TModalFix = class private class function GetModalWindow(SomeWindow: HWnd): HWnd; class function BringToForeground(aWnd: HWnd): Boolean; class function IsThreadTopWindow(aWnd: HWnd): Boolean; public class function FixModalWindow(AppWnd: HWnd): Boolean; end; implementation uses Classes; { TModalFix } class function TModalFix.BringToForeground(aWnd: HWnd): Boolean; const DRAWFLAGS = RDW_ERASE or RDW_INVALIDATE or RDW_UPDATENOW or RDW_ALLCHILDREN; MOVEFLAGS = SWP_NOMOVE or SWP_NOSIZE; SHOWMOVEFLAGS = MOVEFLAGS or SWP_SHOWWINDOW; begin Result := true; (* Das Handle muss gültig und das Fenster sichtbar sein, sonst macht es ja keinen Sinn. *) if (aWnd <> 0) and IsWindowVisible(aWnd) then begin (* - Erst vor ALLE anderen Fenster bringen - Dann das TOPMOST entfernen, damit es nicht vor Fenstern anderer Programme bleibt - Und wieder nach vorn holen *) Result := SetWindowPos(aWnd, HWND_TOPMOST, 0, 0, 0, 0, MOVEFLAGS) and SetWindowPos(aWnd, HWND_NOTOPMOST, 0, 0, 0, 0, MOVEFLAGS) and SetWindowPos(aWnd, HWND_TOP, 0, 0, 0, 0, SHOWMOVEFLAGS); //Dieses muss dann aber neu gezeichnet werden (wieso auch immer) if Result then RedrawWindow(aWnd, nil, 0, DRAWFLAGS); end; end; class function TModalFix.FixModalWindow(AppWnd: HWnd): Boolean; var ModalWnd: HWnd; begin ModalWnd := GetModalWindow(AppWnd); if (ModalWnd <> 0) and not IsThreadTopWindow(ModalWnd) then Result := BringToForeground(ModalWnd) else Result := true; end; class function TModalFix.GetModalWindow(SomeWindow: HWnd): HWnd; var WindowList: TList; hThread: DWORD; function EnumFunc(aWnd: HWnd; List: lParam): Boolean; stdcall; begin (* Nur Fenster, die - kein MDIChild - enabled und - sichtbar sind, in die Liste aufnehmen *) if ((GetWindowLong(aWnd, GWL_EXSTYLE) and WS_EX_MDICHILD) = 0) and IsWindowEnabled(aWnd) and IsWindowVisible(aWnd) then TList(List).Add(Pointer(aWnd)); Result := true; end; begin Result := 0; if SomeWindow <> 0 then begin WindowList := TList.Create; try //Thread-ID ermitteln, andere Threads interessieren uns ja nicht hThread := GetWindowThreadProcessID(SomeWindow); //...und durchgehen EnumThreadWindows(hThread, @EnumFunc, lParam(WindowList)); //genau 1 aktives Fenster -> modal if WindowList.Count = 1 then Result := HWnd(WindowList[0]); finally WindowList.Free; end; end; end; class function TModalFix.IsThreadTopWindow(aWnd: HWnd): Boolean; var NextWnd: HWnd; aThreadID, NextThreadID: DWORD; begin Result := true; if aWnd <> 0 then begin aThreadID := GetWindowThreadProcessID(aWnd); NextWnd := GetWindow(aWnd, GW_HWNDPREV); (* Ermitteln eines Fensters, das zum selben Thread gehört, in der Z-Order weiter oben steht und sichtbar ist. Wird kein solches gefunden, muss aWnd ja das oberste Fenster der Applikation sein. *) while Result and (NextWnd <> 0) do begin NextThreadID := GetWindowThreadProcessID(NextWnd); if (NextThreadID = aThreadID) and IsWindowVisible(NextWnd) then Result := false else NextWnd := GetWindow(NextWnd, GW_HWNDPREV); end; end; end; end.Als günstiger Aufrufzeitpunkt hat sich TApplication.OnIdle erwiesen, welches immer dann ausgeführt wird, wenn die Anwendung gerade nichts zu tun hat.
type TForm1 = class(TForm) procedure FormCreate(Sender: TObject); private { Private-Deklarationen } procedure DoOnIdle(Sender: TObject; var Done: Boolean); public { Public-Deklarationen } end; implementation uses uModalFix; procedure TForm1.DoOnIdle(Sender: TObject; var Done: Boolean); begin if not TModalFix.FixModalWindow(Handle) then MessageBox(0, 'Fehler beim Wiederherstellen modaler Fenster', nil, 0); Done := true; end; procedure TForm1.FormCreate(Sender: TObject); begin Application.OnIdle := DoOnIdle; end;