Anwendung in den Vordergrund holen/Windows-API

Fragen rund um diverse Windows-Versionen, ihr Verhalten unter Xbase++ und den Umgang mit der API

Moderator: Moderatoren

Antworten
Benutzeravatar
Lewi
1000 working lines a day
1000 working lines a day
Beiträge: 830
Registriert: Di, 07. Feb 2006 14:10
Wohnort: Hamburg
Danksagung erhalten: 2 Mal

Anwendung in den Vordergrund holen/Windows-API

Beitrag von Lewi »

Hallo!

Ich suche nach einer Möglichkeit, meine Anwendung in den Vordergrund zu holen, wenn beispielsweise eine Datenübertragung abgeschlossen wurde und der Anwender in der Zwischenzeit in einer anderen Anwendung arbeitet.
Innerhalb des Windows-API bin ich nicht zu recht fündig geworden. Zwar habe ich eine Lösung gefunden, die die Anwendung wieder in den Vordergrund holt, wenn die Anwendung des Fokus verloren hat ( beispielsweise, der Anwender hat die Anwendung minimiert oder er hat über die Schnellstartleiste auf den Desktop gewechselt), sie funktioniert aber nicht, wenn eine andere Anwendung des Fokus hat. Mein bisheriger Lösungsansatz bezieht sich darauf, das Windows-Handle meiner Anwendung zu ermitteln und mittels 2er API-Funktionen in Fordergrund zu bringen. Wie gesagt, funktioniert dieser Lösungsansatz nicht, wenn ein anders Programm dezidiert den Fokus hat.

Ist mein Ansatz über die Window-Funktionen des API´s falsch? Über welche API-Funktionen kann dann eine gestartete Anwendung in den Vordergrund geholt werden?

Gruß, Olaf




***************************************************************************
* Beispiel-Code
***************************************************************************

Code: Alles auswählen

Func Main()
	..
	//Do anythink
	MsgBox( “Nach OK ist die Anwendung 3 sec. im Sleep-Modus“)
	sleep(300)				// Zum test, um in eine andere Anwendung zu springen
	SetDialogFocus()
Return ( NIL )



FUNCTION SetDialogFocus()
     Local nHandle := SetAppWindow():GetHWND()   // Windows-Fenster-Handle ermitteln

     apiSetForegroundWindow( nHandle )
     apiShowWindow( nHandle )
Return ( NIL )



FUNCTION apiSetForegroundWindow( nHandle)
     Local nDll	:= DllLoad("USER32.DLL")
     Local xRet	:= DllCall(nDll,32,"SetForegroundWindow", nHandle)

     DllUnLoad(nDll)
RETURN xRet


FUNCTION apiShowWindow( nHandle)
     LOCAL nDll	:= DllLoad("USER32.DLL")
     LOCAL xRet	:= DllCall(nDll,32,"ShowWindow", nHandle, SW_RESTORE)

     DllUnLoad(nDll)
RETURN xRet

/*Ende
Zuletzt geändert von Lewi am Do, 16. Feb 2006 16:36, insgesamt 1-mal geändert.
Benutzeravatar
Wolfgang Ciriack
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 2934
Registriert: Sa, 24. Sep 2005 9:37
Wohnort: Berlin
Hat sich bedankt: 13 Mal
Danksagung erhalten: 34 Mal
Kontaktdaten:

Beitrag von Wolfgang Ciriack »

Hallo Lewi,
hier ist ein Teil (hab ich mal aus der Alaska Newsgroup) den ich im Zuge des Abprüfens meiner Module benutze. Vielleicht kannst du davon etwas benutzen.

Code: Alles auswählen

#pragma map( XChkPrevApp,   "_XCHKPREVAPP")

#define SW_HIDE             0
#define SW_SHOWNORMAL       1
#define SW_NORMAL           1
#define SW_SHOWMINIMIZED    2
#define SW_SHOWMAXIMIZED    3
#define SW_MAXIMIZE         3
#define SW_SHOWNOACTIVATE   4
#define SW_SHOW             5
#define SW_MINIMIZE         6
#define SW_SHOWMINNOACTIVE  7
#define SW_SHOWNA           8
#define SW_RESTORE          9
#define SW_SHOWDEFAULT      10
#define SW_MAX              10

DLLFUNCTION GetClassNameA( nHwnd, @cBuf, nBufLen ) USING STDCALL FROM USER32.DLL
DLLFUNCTION FindWindowA( @ClassName, WinName )  USING STDCALL FROM USER32.DLL
DLLFUNCTION GetForegroundWindow()               USING STDCALL FROM USER32.DLL
DLLFUNCTION IsIconic( nHwnd )                   USING STDCALL FROM USER32.DLL
DLLFUNCTION GetLastActivePopup( nHwnd )         USING STDCALL FROM USER32.DLL
DLLFUNCTION ShowWindow( nHwnd, nCmdShow )       USING STDCALL FROM USER32.DLL
DLLFUNCTION BringWindowToTop( nHwnd )           USING STDCALL FROM USER32.DLL
DLLFUNCTION SetForegroundWindow( nHwnd )        USING STDCALL FROM USER32.DLL
DLLFUNCTION GetWindowThreadProcessId( nForgroundHwnd, @nRetProcId ) USING STDCALL FROM USER32.DLL

FUNCTION ChkPrevApp( cClass , cWinTitle )
   LOCAL lRet := .F.
   LOCAL nHwndFind, nHwndForeground, nForegroundId
   LOCAL nFindId, nHwndLast

   // Until now I haven't figured out why the second Parameter of FindWindowA()
   // does not work as expected, maybe someone else can find it out...
   // (is this a known bug in the WIN32 API?)
   nHwndFind := FindWindowA( @cClass, @cWinTitle )

   If nHwndFind # 0

      nHwndForeground := GetForegroundWindow()
      nForeGroundId   := GetWindowThreadProcessId( nHwndForeground, 0 )
      nFindId         := GetWindowThreadProcessId( nHwndFind, 0 )

      If nForeGroundId != nFindId .OR. IsIconic( nHwndFind ) # 0

         nHwndLast := GetLastActivePopup( nHwndFind )

         ShowWindow( nHwndLast, SW_RESTORE )

         BringWindowToTop( nHwndLast )
         SetForegroundWindow( nHwndLast )

      EndIF

      lRet := .T.

   EndIF

RETURN lRet
Viele Grüße
Wolfgang
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9355
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 101 Mal
Danksagung erhalten: 361 Mal
Kontaktdaten:

Beitrag von Tom »

Es geht auf Basis dieses Beispiels etwas einfacher:

Code: Alles auswählen

DLLFUNCTION BringWindowToTop( nHwnd )           USING STDCALL FROM USER32.DLL
DLLFUNCTION SetForegroundWindow( nHwnd )        USING STDCALL FROM USER32.DLL

...

* neuen Dialog erzeugen

...

nHwnd := oDialog:GetHwnd() // Handle des neuen Dialogs abfragen
BringWindowToTop(nHwnd)
SetForegroundWindow(nHwnd)
Herzlich,
Tom
Benutzeravatar
Lewi
1000 working lines a day
1000 working lines a day
Beiträge: 830
Registriert: Di, 07. Feb 2006 14:10
Wohnort: Hamburg
Danksagung erhalten: 2 Mal

Beitrag von Lewi »

Hallo Wolfgang,
vielen Dank. Ich werde das Beispiel mal für meine Zwecke umsetzten. Das Ergebnis werde ich hier posten.

Gruß, Olaf
Benutzeravatar
Lewi
1000 working lines a day
1000 working lines a day
Beiträge: 830
Registriert: Di, 07. Feb 2006 14:10
Wohnort: Hamburg
Danksagung erhalten: 2 Mal

Beitrag von Lewi »

Tom hat geschrieben:Es geht auf Basis dieses Beispiels etwas einfacher:

Code: Alles auswählen

DLLFUNCTION BringWindowToTop( nHwnd )           USING STDCALL FROM USER32.DLL
DLLFUNCTION SetForegroundWindow( nHwnd )        USING STDCALL FROM USER32.DLL

...

* neuen Dialog erzeugen

...

nHwnd := oDialog:GetHwnd() // Handle des neuen Dialogs abfragen
BringWindowToTop(nHwnd)
SetForegroundWindow(nHwnd)

Hallo Tom,
nachdem mir die DLLFUNKTIONEN klar geworden sind, bin ich zum Ergebnis gekommen: Ist die gleiche Lösung wie meine und sie funktioniert auch nicht. *g*
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9355
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 101 Mal
Danksagung erhalten: 361 Mal
Kontaktdaten:

Beitrag von Tom »

Hallo, Lewi.

Ich kann bei Dir kein BringWindowToTop() entdecken. Bei mir funktioniert das jedenfalls einwandfrei. 8)

Code: Alles auswählen

FUNCTION DlgToFront(oDlg)
LOCAL nDlgHandle:=oDlg:GetHwnd()
BringWindowToTop( nDlgHandle )
SetForegroundWindow( nDlgHandle )
RETURN NIL

* irgendwo neuen Dialog "oDialog" erzeugen
oDialog:show()
DlgToFront(oDialog)
Herzlich,
Tom
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9355
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 101 Mal
Danksagung erhalten: 361 Mal
Kontaktdaten:

Beitrag von Tom »

Übrigens: Danke an alle! Ich habe schon eine ganze Weile nach den API-Funktionen gestöbert und nix gefunden. Jetzt schwuppt meine Applikation immer in den Vordergrund, nachdem sie gestartet wurde, womit ich gleichzeitig ein Problem löse, das mit einer Analoguhr im Hauptmenü zu tun hatte. Deren PS habe ich mit GraSaveScreen() weggespeichert und mit jedem Repaint des Hauptfensters restauriert, aber wenn das Hauptfenster in diesem Moment nicht im Vordergrund war, wurde der entsprechende Ausschnitt des Desktops gespeichert und in diesem Ausschnitt angezeigt. :lol:

Also - danke nochmals! =D>
Herzlich,
Tom
Benutzeravatar
Lewi
1000 working lines a day
1000 working lines a day
Beiträge: 830
Registriert: Di, 07. Feb 2006 14:10
Wohnort: Hamburg
Danksagung erhalten: 2 Mal

Und hier die Lösung!

Beitrag von Lewi »

Hallo miteinander,
alle hier bisher vorgeschlagenen Lösungen sowie die in den ALASKA-Newsgroups, funktionien nur eingeschränkt:
- entweder blinkt in der Taskleiste der Bottom für die eigene Anwendung ohne das das Fenster angezeigt wird,
wenn ein anderes Programm den Fokus hat oder,
- das Fenster wird nur in den Vordergund geholt, wenn es minimiert ist oder
- oder das eigene Programmfenster hatte den Fokus, bevor über die Schnellstartleiste zum Desktop gewechselt wurde
- oder es funktioniert gar nichts ;-)

Wie auch immer, ich habe eine Lösung gefunden, die die eigene Anwendung in den Vordergrund holt, unabhängig davon, ob sie
minimiert ist, ein anderes Programm den Fokus hat oder zum Desktop gewechselt wurde.

Ich bedanke mich bei allen für die Anregungen.

Gruß, Olaf



Hier nun ein Beispiel mit den dazugehörigen API-Funktionen
************************************************************************************************************

Code: Alles auswählen

Func main()
      Local nHandle    := SetAppWindow():GetHWND()			// Fenster-Handle der eigenen Anwendung
      Local nMyThread											// Thread-Id der eigenen Anwendung
      Local nAktThread										// Thread-Id des aktuellen Fensters
	
        nMyThread	:= apiGetWindowThreadProcessId(nHandle)
        msgbox("Nach OK 3 sec. Pause ....")
        sleep(300)												// In dieser Zeit kann zum Test in eine andere Anwendung gewechselt werden

        nAktThread := apiGetWindowThreadProcessId(      apiGetForegroundWindow() )	

        IF nMyThread == nAktThread								// Wenn aktuelles Fenster die eigene Anwendung ist, reicht ein SetForeGroundWindow
                apiSetForeGroundWindow( nHandle )
           else
                apiAttachThreadInput( nAktThread, nMyThread, TRUE )	// Setzt den Input-Focus auf die eigene Anwendung
                apiSetForeGroundWindow( nHandle )					// Fenster in den Fordergrund holen
                apiShowWindow( nHandle )							// Fenster Anzeigen (falls minimiert, wird es maximiert)
          ENDIF
          MsgBox("End of program")
Return ( NIL )


/************************************************************************
// API-Funktion zur Ermittlung des Fenster Handles der aktuellen Fensters
*************************************************************************/
FUNCTION apiGetForegroundWindow( nHandle)
        LOCAL nDll       := DllLoad("USER32.DLL")
        LOCAL xRet      := DllCall(nDll,32,"GetForegroundWindow", nHandle)
        DllUnLoad(nDll)
RETURN ( xRet )


/***************************************************************************************
// API-Funktion, um ein Fenster (nHandle) in den Fordergrund zu bringen ( Top of Z_order)
***************************************************************************************/
FUNCTION apiSetForeGroundWindow( nHandle)
        LOCAL nDll       := DllLoad("USER32.DLL")
        LOCAL xRet      := DllCall(nDll,32,"SetForegroundWindow", nHandle)
        DllUnLoad(nDll)
RETURN ( xRet )


/****************************************************************************************
// API-Funktion zur Anzeige eines Fenster. SW_RESTORE ist in diesem Zusammenhang wichtig
// damit auch ein minimiertes Fenster expandiert wird
****************************************************************************************/
FUNCTION apiShowWindow( nHandle)
        LOCAL nDll      := DllLoad("USER32.DLL")
        LOCAL xRet     := DllCall(nDll,32,"ShowWindow", nHandle, SW_RESTORE)
        DllUnLoad(nDll)
RETURN ( xRet )


/****************************************************************************
// API-Funktion zur Ermittlung der Prozess-ID des übergebenen Fenster-Handles
****************************************************************************/
Function apiGetWindowThreadProcessId( nHandle)
        Local nDll       :=DllLoad("USER32.DLL")
        Local xRet
        Local nPid      := NIL	// wird hier nicht gebraucht
        xRet              :=DllCall(nDll,32,"GetWindowThreadProcessId", nHandle, nPid)
        DllUnLoad(nDll)
Return ( xRet )


/************************************************************
//  API-Funktion um die Eingabeverarbeitung von dem aktuellem Prozess 
//  (nAttach) auf einen anderen Prozess ( nAttachTo [hier die eigene
//  Anwendung] ) zu setzen. Dies ist erforderlich, damit
//  SetForeGroundWindow ab Windows 95 /NT 4.0 korrekt arbeitet. Wird
//  diese Funktion nicht in Verbindung mit SetForegroundWindow 
//  aufgerufen , blinkt nur der Bottom der eigenen Anwendung innerhalb 
//  der Funktionsleiste.
************************************************************/
Function apiAttachThreadInput( nAttach, nAttachTo, lSet )
        LOCAL nDll     := DllLoad("USER32.DLL")
        Local xRet      := DllCall(nDll,32,"AttachThreadInput", nAttach, nAttachto, lSet )
        DllUnLoad(nDll)
Return ( xRet )
Benutzeravatar
michael32710
UDF-Programmierer
UDF-Programmierer
Beiträge: 76
Registriert: Sa, 17. Nov 2007 11:02
Wohnort: Niedersachsen
Kontaktdaten:

Re: Anwendung in den Vordergrund holen/Windows-API

Beitrag von michael32710 »

Vielen Dank für dieses gute Beispiel-Programm.
Zwei kleine Ergänzungen:
1. Im Beispiel fehlt
#DEFINE SW_RESTORE 9

2. Das Beispiel hat bei mir auch auf Win VISTA und Win 7 funktioniert.
MfG
Michael
Antworten