Seite 1 von 2

Eigenes Programm in den Vordergrund holen [erledigt]

Verfasst: Sa, 13. Feb 2016 9:20
von satmax
Hallo,

ich schaffe es nicht, mein eigenes Programm in den Vordergrund zu holen. :banghead:

Hintergrund: ich erhalte eine Windows Nachricht, regagiere darauf, führe eine kleine Aktion aus und soll mein Programm dann in den Vordergrund schalten.

Das einzige was ich schaffe ist, das mein Icon in der Task-Leiste zu blinken beginnt.

Versucht habe ich unter anderem (gekürzt):

Code: Alles auswählen

AllowSetForegroundWindow(ASFW_ANY) 
aWnd:= WildFindWindow( public_cTitle )
IF LEN(aWnd) >0
  debugprint("Window found!", aWnd[1][1])
  hWND:= aWnd[1][1]
  ShowWindow(hWND,SW_RESTORE)
  BringWindowToTop(hWND)
   SetForegroundWindow(hWND)
  debugPrint("tdBringtotop",tdBringToTop(public_cTitle,"RESTORE"))

  ShowWindow(public_App:getHWnd(),SW_RESTORE)
  BringWindowToTop(public_App:getHWnd()) 
  	
  AllowSetForegroundWindow(ASFW_ANY) 
   SetForegroundWindow(public_App:getHWnd())

  	
   SetForegroundWindow(hWND)
   ShowWindowAsync(hWnd,1)
   SetAppWindow():AlwaysOnTop := .T.	

  public_App:AlwaysOnTop := .T.	
  public_App:show()
  CenterControl(public_App)

endif
Alles doppelt und dreifach, halt beim testen....

Das CenterControl() greift, aber meine App kommt nicht in den Vordergrund, lediglich das Symbol in der Iconleiste beginnt zu blinken.

Woran kann das liegen?

Re: Eigenes Programm inden Vordergrund holen

Verfasst: Sa, 13. Feb 2016 10:17
von Koverhage
Eventuell ein maximize ?

Re: Eigenes Programm inden Vordergrund holen

Verfasst: Sa, 13. Feb 2016 10:21
von satmax
Koverhage hat geschrieben:Eventuell ein maximize ?
wird maximiert, kommt trotzdem nicht in den Vordergrund.

Re: Eigenes Programm inden Vordergrund holen

Verfasst: Sa, 13. Feb 2016 10:34
von satmax
Das funktioniert, "blinkt" aber einmal unschön:

Code: Alles auswählen

SetAppWindow():AlwaysOnTop := .T.	
SetAppWindow():configure()
SetAppWindow():AlwaysOnTop := .f.	
SetAppWindow():configure()

Re: Eigenes Programm inden Vordergrund holen

Verfasst: Sa, 13. Feb 2016 13:57
von AUGE_OHR
satmax hat geschrieben:Das einzige was ich schaffe ist, das mein Icon in der Task-Leiste zu blinken beginnt.
...
Woran kann das liegen?
wenn ich ein Programm unter XP gestartet habe erscheint es nicht gleich in der Task-Leiste sondern erst wenn ich es minimiere.

wenn unter Win7 ein Icon in der Task-Leiste blinkt bedeutet es das es gerne vom User den Focus haben möchte -> aktives "sichtbares" Fenster.

wenn ich unter XP eine solche Aktion machen wollte müsste zunächst das Icon, durch "Minimize", in die Task-Leiste gebracht werden. ein Klick auf das Icon würde es "restoren".

ich würde also nun versuchen deine Applikation, auch wenn du die "siehst", zu "restoren" ( oder maximize )

Code: Alles auswählen

#define WM_SYSCOMMAND      0x0112
#define SC_MINIMIZE        0xF020
#define SC_MAXIMIZE        0xF030
#define SC_RESTORE         0xF120

* -------------------------------- *
FUNCTION MaximizeWindow( hWnd )
   DllCall( "User32.DLL", DLL_STDCALL, "SendMessageA", ;
            hWnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0, 0 )
RETURN nil
* -------------------------------- *
FUNCTION MinimizeWindow( hWnd )
   DllCall( "User32.DLL", DLL_STDCALL, "SendMessageA", ;
            hWnd, WM_SYSCOMMAND, SC_MINIMIZE, 0, 0 )
RETURN nil
* -------------------------------- *
FUNCTION RestoreWindow( hWnd )
   DllCall( "User32.DLL", DLL_STDCALL, "SendMessageA", ;
            hWnd, WM_SYSCOMMAND, SC_RESTORE, 0, 0 )
RETURN nil

Re: Eigenes Programm inden Vordergrund holen

Verfasst: Sa, 13. Feb 2016 16:42
von satmax
Jimmy, das geht so auch nicht.

Hilfreich ist RestoreWindow(hWnd) nur, um im Falle eines minimierten Fensters das Fenster wieder herzustellen:

So funktioniert das schon ganz brauchbar:

Code: Alles auswählen

....
elseif nMsg == WM_USER_SHOWDISPO   
	debugprint("WM_USER_SHOWDISPO")
	aWnd:= WildFindWindow( public_cTitle )
	
	IF LEN(aWnd) >0
		RestoreWindow(aWnd[1][1])      // Falls App minimiert
		lOnTop:=SetAppWindow():AlwaysOnTop
		SetAppWindow():AlwaysOnTop := .T.	  // Trick um App in den Vordergrund zu bringen
		SetAppWindow():configure()
		SetAppWindow():AlwaysOnTop := lOnTop  // Ur Status wiederherstellen
		SetAppWindow():configure()
	else	
		debugprint("Handle nicht gefunden")
	endif
endif
return DllExecuteCall( _tfpDefWindowProc_ , hWnd , nMsg , wp , lp )

Re: Eigenes Programm inden Vordergrund holen

Verfasst: Mo, 15. Feb 2016 6:41
von Herbert
AlwaysOnTop wäre dann wohl auch nicht unbedingt das Beste, es liesse sich neben anderen Anwendungen nicht mehr hinter jene anderen Fenster verstecken.
Nehme aber an, dass du unbedingt alles versuchst, das Ding sichtbar zu bekommen.

WildFindWindow kenne ich nicht. Bringt das Zeichen zurück? Andernfalls müsstest du bloss auf >0 testen. Scheinst aber doch in die Schlaufe zu kommen.
Blöde Frage: Ist dein Mainwindow visible definiert?

Ich teste übrigens so, hwndlg ist übrigens nur dann <> 0, wenn das Programm bei erneutem Aufruf bereits lief. Daher meine blöde Frage oben...

Code: Alles auswählen

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

// Appsys...
    hWndDlg := DllCall("User32.dll",DLL_STDCALL,"FindWindowA",0,"ZUSCALC Meetingpoint")
    IF !(hWndDlg == 0)    // das Programm wurde bereits füher aufgerufen - hervorholen
      DllCall("User32.dll",DLL_STDCALL,"SetForegroundWindow",hWndDlg)
      DllCall("User32.dll",DLL_STDCALL,"BringWindowToTop",hWndDlg)
      DllCall("User32.dll",DLL_STDCALL,"ShowWindow",hWndDlg,1)
      DllCall("User32.dll",DLL_STDCALL,"UpdateWindow",hWndDlg)
    ENDIF

Re: Eigenes Programm inden Vordergrund holen

Verfasst: Mo, 15. Feb 2016 7:32
von satmax
WildFindWindow(cTitile) liefert mit ein Array mit all den Fenstern auf die der Titel passt, in diesem Fall eines.
Jedes Element enthalt {hWin,cTitleKomplett,num,ProzessID, cNameExe}

Das Handele stimmt, denn ich kann das Fenster verschieben, zentrieren, maximieren, alles halt im Hintergrund.

AlwaysOnTop aktiviere ich nur ganz kurz, wird ja 2 Zeilen später wieder aufgehoben. Das ist eben der Trick, aber so funktioniert es. Auch bei Deiner Variante blinkt nur das Icon in der Taskleiste.

Re: Eigenes Programm inden Vordergrund holen

Verfasst: Mo, 15. Feb 2016 8:58
von AUGE_OHR
satmax hat geschrieben:Das Handele stimmt, denn ich kann das Fenster verschieben, zentrieren, maximieren, alles halt im Hintergrund.
em ... äh ... und was läuft im Vordergrund ?

Re: Eigenes Programm inden Vordergrund holen

Verfasst: Mo, 15. Feb 2016 9:54
von Herbert
Ah so, das Fenster ist da, kommt aber nicht im Vordergrund...
Dann ist wohl dasjenige Fenster (diejenige App), welche dein Programm verdeckt Schuld an der Sache und nicht dein Programm.
Oder sind alle anderen Fenster (Explorer usw.) auch stets davor?

Re: Eigenes Programm inden Vordergrund holen

Verfasst: Mo, 15. Feb 2016 9:57
von brandelh
Ist da irgendwo ein Systemdialog aktiv (Messagebox etc. ) ?

Re: Eigenes Programm inden Vordergrund holen

Verfasst: Mo, 15. Feb 2016 13:10
von satmax
AUGE_OHR hat geschrieben:
satmax hat geschrieben:Das Handele stimmt, denn ich kann das Fenster verschieben, zentrieren, maximieren, alles halt im Hintergrund.
em ... äh ... und was läuft im Vordergrund ?
1,2,3 verschiedene andere Programme, meines ist halb halb verdeckt, von allen Programmen. Habe 3440x1440 Monitorauflösung. Auch beim halbverdeckten Programm erkennt man ganz gut wenn es zentriert, verschoben oder maximiert wird.

@Herbert: auch der Explorer verdeckt es halb.

@Hubert: nein keine Messagebox aktiv

@AUGE_OHR: egal, jedes Programm verdeckt einen Teil davon.

Ich zeig euch ein Foto.

Re: Eigenes Programm inden Vordergrund holen

Verfasst: Mo, 15. Feb 2016 13:35
von brandelh
Was passiert, wenn du es direkt anklickst ? Eventuell sind die anderen auch auf "always on top" eingestellt.

Re: Eigenes Programm inden Vordergrund holen

Verfasst: Mo, 15. Feb 2016 13:41
von satmax
Nein, das geht alles problemlos. Keines der anderen Programme sind onTop. Alle Programme sind von uns (Explorer ausgenommen. :) )

Re: Eigenes Programm inden Vordergrund holen

Verfasst: Di, 16. Feb 2016 5:48
von AUGE_OHR
satmax hat geschrieben:

Code: Alles auswählen

   SetAppWindow():AlwaysOnTop := .T.	
   CenterControl(public_App)
Das CenterControl() greift, aber meine App kommt nicht in den Vordergrund, lediglich das Symbol in der Iconleiste beginnt zu blinken.
versuch mal

Code: Alles auswählen

SetAppWindow(public_App)
SetAppFocus(public_App)

Re: Eigenes Programm inden Vordergrund holen

Verfasst: Di, 16. Feb 2016 5:56
von Wolfgang Ciriack
Also ich benutze diese Aufrufe

Code: Alles auswählen

   DllCall( "User32.dll", DLL_STDCALL, "SetForegroundWindow", hWndDlg )
   DllCall( "User32.dll", DLL_STDCALL, "BringWindowToTop", hWndDlg )
   DllCall( "User32.dll", DLL_STDCALL, "ShowWindow", hWndDlg, 1 )
   DllCall( "User32.dll", DLL_STDCALL, "UpdateWindow", hWndDlg )

Re: Eigenes Programm inden Vordergrund holen

Verfasst: Di, 16. Feb 2016 7:08
von Herbert
Hast du das Phänomen auch auf einem anderen Rechner?

Re: Eigenes Programm inden Vordergrund holen

Verfasst: Di, 16. Feb 2016 8:01
von AUGE_OHR
werden die Fenster automatisch aktive wenn die Maus "drüber fährt" ?
Win10Maus.jpg
Win10Maus.jpg (83.98 KiB) 12821 mal betrachtet

Re: Eigenes Programm inden Vordergrund holen

Verfasst: Di, 16. Feb 2016 8:08
von brandelh
:alwaysontop wird nur bei create() oder configure() ausgewertet, aber hast du die Funktionen des Fensters schon versucht ?

:toBack()
:toFront()

Re: Eigenes Programm inden Vordergrund holen

Verfasst: Di, 16. Feb 2016 8:20
von satmax
@Jimmy: same problem

@Wolfgang: hatten wir schon :)

@herbert: ja, zumindest auf Win 8.1 win 10 und Terminalserver 2012

Wie gesagt, ich muss mich ja selbst in den Vordergrund holen. Das xBase++ ist in etwa so aufgebaut:

Code: Alles auswählen


// The receiver window will run in it's own thread
function InitTheReceiver()
local oThread
oThread := Thread():New()
oThread:Start({||ReceiverThread()})
return NIL
...
ReceiverThread()  // ist praktisch ein Hidden Fenster
...
oCls:lpszClassName := WND_CLASSNAME_DISPO //  autogenerated with UUIDGen.exe
..
hWndReceiver := DllExecuteCall( _tfpCreateWindowEx_ ,;
                                 0 ,; // No exStyle
                                 hReceiverClass,;// Window Class handle
                                 0,; // No Title 0
                                 0xC40000,; // dwStyle WS_OVERLAPED
                                 0,0,0,0,; // x,y,cx,cy
                                 0,; // hWndParent 
                                 0,; // hMenu
                                 AppInstance(),;
                                 0) // empty LPParam
..

// Hier bekomme ich die Nachrichten von den anderen Programmen
function ReceiverWndProc( hWnd , nMsg , wp , lp )
...
elseif nMsg == WM_CLOSE
   // Destroy the receiver window
   DllExecuteCall( _tfpPostMessage_ , hWnd, WM_DESTROY , 0, 0)
   DllExecuteCall( _tfpPostMessage_ , hWnd, WM_NCDESTROY, 0, 0)
   return 1
elseif nMsg == WM_NCDESTROY
...
elseif nMsg == WM_USER_CALC_ROUTE_4_AUFTRAG_DONE
// re-read data from sql
....
elseif nMsg == WM_USER_SHOWDISPO 
  debugprint("WM_USER_SHOWDISPO")
// Hier hole ich mein eigenes Programm in den Vordergrund was im Moment nur so geht:
  debugprint("WM_USER_SHOWDISPO")
  aWnd:= WildFindWindow( public_cTitle )
		
  IF LEN(aWnd) >0
    RestoreWindow(aWnd[1][1])
    lOnTop:=SetAppWindow():AlwaysOnTop
    SetAppWindow():AlwaysOnTop := .T.	     // Trick aber funktioniert.
    SetAppWindow():configure()
    SetAppWindow():AlwaysOnTop := lOnTop
    SetAppWindow():configure()
  else	
    debugprint("Handle nicht gefunden")
  endif
ENDIF

...
// DefWindowProc() will process the rest of the cases
return DllExecuteCall( _tfpDefWindowProc_ , hWnd , nMsg , wp , lp )


Re: Eigenes Programm inden Vordergrund holen

Verfasst: Di, 16. Feb 2016 8:23
von satmax
@Hubert

SetAppWindow():toFront() bringt auch nichts.

Re: Eigenes Programm inden Vordergrund holen

Verfasst: Di, 16. Feb 2016 12:14
von AUGE_OHR
satmax hat geschrieben:

Code: Alles auswählen

// The receiver window will run in it's own thread
function InitTheReceiver()
local oThread
oThread := Thread():New()
oThread:Start({||ReceiverThread()})
return NIL

...

function ReceiverWndProc( hWnd , nMsg , wp , lp )
...
elseif nMsg == WM_CLOSE
elseif nMsg == WM_NCDESTROY
elseif nMsg == WM_USER_CALC_ROUTE_4_AUFTRAG_DONE
elseif nMsg == WM_USER_SHOWDISPO 
ENDIF

...
// DefWindowProc() will process the rest of the cases
return DllExecuteCall( _tfpDefWindowProc_ , hWnd , nMsg , wp , lp )
interessant ... und nicht mit ot4xb ... :-k
ich "denke" es hat was mit den Xbase++ "internen" Threads zu tun. Pablo macht das mit

Code: Alles auswählen

   ot4xb_subclasswindow( ::hDlg , Self ,NIL , "ReceiverWndProc" )
...
INLINE METHOD ReceiverWndProc(hWnd,nMsg,wp,lp,ctx)
das ganze läuft dann im Xbase++ "GUI-Thread". Man hat aber damit noch keine "Kommunikation" zur Xbase++ Eventloop.

sag mir ob das der Fall sein könnte was das komische Verhalten erklären würde.

:idea: Idee : du öffnest eine (Dummy) DBF in ReceiverThread() EXCLUSIVE
nun lässt du im Main Xbase++ einen Thread laufen der ebenfalls die (Dummy) DBF öffnen möchte ... geht nicht solange dein externer Thread läuft.
wenn du die nun, im Xbase++ Thread, die (Dummy) DBF öffnen kannst dann schickst du ein PostAppEvent() an deine Main() :)

Re: Eigenes Programm inden Vordergrund holen

Verfasst: Di, 16. Feb 2016 13:35
von satmax
Ist von Pablo:
Callback Compiler for Xbase++ Ver 1.0.17
(c) Pablo Botella Navarro. (2008)
http://www.xbwin.com
---------------------------------------------------------------------------

What's xppcbk.exe?
------------------
xppcbk.exe generate a OBJ from a simple syntax script
allowing your Xbase++ functions act as true callbacks
in any API that require a callback pointer.
....

Es geht nicht darum das ein anderes Programm das xBase++ Programm in den Vordergrund holt. Es geht darum, das sich das xBase++ selbst in den Vordergrund bringt.

Ich erhalte viele verschiedene Windows Nachrichten von 2 anderen Programmen und muss eben darauf reagieren. Das klappt auch alles.

Was nicht geht, ist das sich mein xBase++ Programm selbst in den Vordergrund schaltet, ausser eben mit diesem Trick ganz kurz auf AlwaysOnTop:=.t. zu schalten um es dann sofort wieder abzuschalten.

Die callback Function arbeitet völlig korrekt. Man schickt einfach eine Windowsnachricht an das unsichtbare Fenster mit der UUID. Mein Thread verarbeitet dann die Nachricht und/oder gibt sie weiter. Das passt alles und macht keine Probleme.

Re: Eigenes Programm inden Vordergrund holen

Verfasst: Mi, 17. Feb 2016 2:04
von AUGE_OHR
satmax hat geschrieben:Ist von Pablo:
Callback Compiler for Xbase++ Ver 1.0.17
(c) Pablo Botella Navarro. (2008)
http://www.xbwin.com
aha ... Ja ... damit geht es natürlich auch.
satmax hat geschrieben:Es geht nicht darum das ein anderes Programm das xBase++ Programm in den Vordergrund holt. Es geht darum, das sich das xBase++ selbst in den Vordergrund bringt.
schon verstanden aber es darum "wo" du dich befindest wenn du das versuchst.

du arbeitest ja mit einem (Xbase++) Thread wo du die Daten empfängst. es ist aber nicht der (Xbase++) "Main Thread" ...
ich würde aus dem Thread an den "Main" Thread eine Nachricht schicken ( oder mittels DBF ) damit in der Main Loop die App in den Vordergrund geholt wird.

Re: Eigenes Programm inden Vordergrund holen

Verfasst: Fr, 19. Feb 2016 8:32
von satmax
Hallo Jimmy,

ich habe nun versucht mein Programm im Haupt Event Loop (also im Main Tread) in den Vordergrund zu holen, geht auch nicht, gleicher Effekt.