Prozess im Vordergrund von eigener Anwendung erstellen?



  • Danke für die Antwort! 🙂

    ist "WS_EX_TOPMOST" nicht nur für CreateWindow?
    Kann man damit auch das Formular eines "fremden" Prozesses ändern?
    Den Prozess starte ich mit CreateProcess... 😕



  • Noctua-Dev schrieb:

    Danke für die Antwort! 🙂

    ist "WS_EX_TOPMOST" nicht nur für CreateWindow?
    Kann man damit auch das Formular eines "fremden" Prozesses ändern?
    Den Prozess starte ich mit CreateProcess... 😕

    Mit SetWindowPos kannst Du jedenfalls auch Topmost ändern. Ob das auch mit fremden Fenstern geht, hab ich allerdings nicht ausprobiert.



  • Habe es gerade getestet:

    Mit WS_EX_TOPMOST setzt man das Fenster (was zu dem Handle gehört) in den Vordergrund. Leider verschwindet das Fenster beim Anklicken des anderen Fensters wieder im Hintergrund.



  • @Noctua-Dev
    Du kannst mal versuchen ob es mit SetParent funktioniert: https://msdn.microsoft.com/en-us/library/windows/desktop/ms633541.aspx
    Ist aber auf jeden Fall ein Hack - würde ich eher nicht empfehlen.

    Ansonsten kannst du periodisch nachgucken ob das Fenster des anderen Programms hinter deines verschoben wurde, und bei Bedarf erneut SetWindowPos aufrufen.

    @mgaeckler
    Soweit ich weiss geht SetWindowPos auch mit fremden Fenstern. Kann höchstens sein dass da Permissions geprüft werden. Wenn der fremde Prozess aber vom eigenen gestartet wurde, dann läuft er auch üblicherweise mit dem selben Account, und dann sollte es diesbezüglich keine Probleme geben.



  • Ich arbeite gerade mit dem Borland c++ Builder 6.0.
    Wenn ich die Funktion SetParent aufrufe kann ich als Parameter nur "TWinControl *" angeben. Bei einem Handle erhalte ich diesen Fehler:

    [C++ Fehler] Unit1.cpp(24): E2034 Konvertierung von 'void * *' nach 'TWinControl *' nicht möglich

    Obwohl unter https://msdn.microsoft.com/en-us/library/windows/desktop/ms633541(v=vs.85).aspx die Angabe zweier Handles möglich sein sollte??

    Selbst wenn ich z.B. ein weiteres Formular (TWinControl 😉 angebe, befindet sich dies "in" meinem Hauptformular. 😮



  • Noctua-Dev schrieb:

    Ich arbeite gerade mit dem Borland c++ Builder 6.0.
    Wenn ich die Funktion SetParent aufrufe kann ich als Parameter nur "TWinControl *" angeben. Bei einem Handle erhalte ich diesen Fehler:

    [C++ Fehler] Unit1.cpp(24): E2034 Konvertierung von 'void * *' nach 'TWinControl *' nicht möglich

    Obwohl unter https://msdn.microsoft.com/en-us/library/windows/desktop/ms633541(v=vs.85).aspx die Angabe zweier Handles möglich sein sollte??

    Selbst wenn ich z.B. ein weiteres Formular (TWinControl 😉 angebe, befindet sich dies "in" meinem Hauptformular. 😮

    Nimm SetParent nicht von der vcl. ::SetParent (...);



  • @Noctua-Dev
    Was mgaeckler dir damit sagen möchte:
    Die VCL-Fensterklasse definiert eine eigene Funktion die SetParent heisst. Weil das für reine VCL-Anwendungen bequemer ist wenn man einfach den TWinControl -Zeiger übergeben kann statt sich das Fensterhandle raussuchen zu müssen.

    Und wenn du statt dessen die SetParent Funktion aus dem globalen Namespace aufrufen möchtest, dann musst du zwei Doppelpunkte vorn dranschreiben, also ::SetParent .

    ps:
    Ich hab' mir angewöhnt überall wo ich WinAPI Funktionen aufrufe immer ::Funktionsname zu schreiben. Dadurch sieht man u.A. auch gleich wo direkt auf die WinAPI zugegriffen wird. Muss man aber nicht machen, ich erwähnte das nur weil's thematisch gerade dazupasst.



  • Danke!

    Rufe jetzt richtige Funktion auf. Trotzdem befindet sich jetzt das Fenster in dem Formular... Gibt es auch eine Möglichkeit das Fenster vor das Formular zu setzen, oder wird bei einer MessageBox kontrolliert ob die Meldung noch im Vordergrund ist?

    😞



  • Naja, kann sein dass es mit SetParent doch nicht geht.

    Was du machen willst wäre das Owner-Window zu ändern, nicht das Parent-Window.
    An einigen Stellen in der WinAPI werden für Parent und Owner die gleichen Funktionen/Member/Parameter verwendet, daher dachte ich es sollte mit SetParent funktionieren. Muss aber nicht sein dass das so ist, ich hab's nicht ausprobiert.

    Bzw. bist du sicher dass das Fenster der anderen Anwendung ein Top-Level Fenster ist? Wenn du SetParent auf ein Child-Window aufrufst, dann ist klar dass es danach IN deiner Form drinnen ist, und nicht davor -- weil halt Child Window.



  • Aaaaaah,

    hier
    http://stackoverflow.com/questions/133122/how-to-change-a-window-owner-using-its-handle
    steht dass man SetWindowLongPtr(..., GWLP_HWNDPARENT, ...) verwenden kann.

    Das könntest du mal probieren.



  • Das sieht vielversprechend aus!
    http://stackoverflow.com/questions/133122/how-to-change-a-window-owner-using-its-handle

    SetWindowLongPtr( win32window, GWL_HWNDPARENT, formhandle );
    

    Problem ist nur: laut MSDN ist die Funktion wie folgt deklariert:

    LONG_PTR WINAPI SetWindowLongPtr(
      _In_  HWND hWnd,
      _In_  int nIndex,
      _In_  LONG_PTR dwNewLong
    );
    

    Der dritte Parameter (dwNewLong) sollte laut Beispiel das Handle des Formulars (formhandle) sein. Natürlich kann ich als long kein HWND übergeben. 🙄

    [C++ Fehler]: E2034 Konvertierung von 'void *' nach 'long' nicht möglich

    Wie kann ich trotzdem das Handle des Formulars übergeben?



  • Einfach casten.

    reinterpret_cast<LONG_PTR>(deinHwndWert)

    Der reinterpret_cast ist in dem Fall auch kein Hack, sondern vom MS ganz klar so vorgesehen.

    Wichtig ist nur dass du die " ...Ptr " Funktion verwendest und auch LONG_PTR beim Casten verwendest, sonst bekommst du ein Problem wenn du mal für 64 Bit kompilierst.



  • ps:
    Wichtig:
    GWL ** P ** _HWNDPARENT statt GWL_HWNDPARENT verwenden wenn du SetWindowLong ** Ptr **verwendest.

    Sonst wird das mit 64 Bit vermutlich wieder net richtig funktionieren 🙂



  • Vielen Dank!! Funktioniert herrlich!!! 😃 😃

    Nur noch eine Kleinigkeit:
    Das andere Fenster sitzt im Vordergrund und minimiert sich auch mit. Man kann aber trotzdem noch das Parent-Formular bedienen. Muss man wirklich einen Timer oder Thread erstellen, der ein MessageBeep ausführt und den Fokus auf das Formular setzt, sobald man auf das Hauptformular klickt, oder kann man da auch mit der WinAPI arbeiten? 😉

    Trotzdem: Schön dass es funktioniert!! 👍



  • Welches Parent-Formular?
    Verstehe grad nicht was du meinst.
    Das Parent-Formular in deiner Applikation? Oder in der Fremden?

    Mach vielleicht mal Screenshots die das ganze verdeutlichen.

    Bzw. falls es um deine Applikation geht, kannst du natürlich auch hier Window-Ownership verwenden. Und/oder modale Dialoge.

    ps: Das ist immer noch ein Hack, und ich würde es nur begrenzt empfehlen. Es kann durchaus Applikationen geben die ... anfangen komische Dinge zu tun wenn man an ihren Fenstern in dieser Art rumpfuscht - also Owner-Window ändert oder dergleichen.

    pps: Das "ist in dem Fall auch kein Hack" oben bezieht sich auf den reinterpret_cast , nicht auf das Ändern des Owner-Windows.



  • Hier sind die Links zu den Filmen, die hoffentlich das Problem näher führen.

    Film1 (meine Anwendung):
    http://www.noctua-development.de-info.de/downloads/Meine_Anwendung.wmv

    Film2 (MessageBox Anwendung -> wie es sein sollte)
    http://www.noctua-development.de-info.de/downloads/MessageBox_Beispiel.wmv

    Natürlich könnte man diesen Effekt selber erzielen, aber ich habe die Hoffnung noch nicht aufgegeben, dass es etwas Hübsches aus der WinAPI gibt. 😃



  • OK, cool, ich denke jetzt hab' ich verstanden was du willst 💡 🙂
    Du willst bloss dass dein Dialog "gesperrt" ist, so lange das andere Programm läuft, korrekt?

    Das sollte doch einfach sein:
    Mach eine kleine Dialog-Klasse, die nen Mini-Dialog ala "[...warte auf externe Anwendung...]" oder so anzeigt (theoretisch könner man den Dialog, falls gewünscht, auch komplett unsichtbar bekommen).

    Dieser Dialog sollte vom Benutzer nicht schliessbar sein, also die entsprechenden Handler-Funktionen überschreiben (bei MFC wären das z.B. OnCancel und OnClose).

    Einfacherweise würde ich diesem Dialog dann auch die Aufgabe übertragen das externe Programm zu starten, und zu überwachen wann das externe Programm fertig wird (z.B. einfach nen Timer und dann mit WaitForSingleObject(hProcess, 0) periodisch checken ob der Prozess noch läuft). Und wenn der externe Prozess fertig ist, schliesst sich der Dialog von selbst.

    Und diesen Dialog rufst du dann einfach modal auf. Wodurch genau das selbe passiert wie bei einer MessageBox, nämlich dass das Fenster darunter blockiert wird.

    Wobei du dir überlegen solltest ob es nicht besser wäre einfach nur alle Controls (inklusive dem Fenster-schliess-"X") zu disablen während das externe Programm läuft. Ich persönlich finde das nämlich immer nervig dass ich, wenn so ein modales Gedöns offen ist, das darunterliegende Fenster nichtmal verschieben kann.



  • ps: Du kannst natürlich auch mal probieren was passiert wenn du EnableWindow(myDialog, false) aufrufst.
    Oder sonst ein wenig googeln ob es nen einfachen Mechanismus gibt den Effekt eines modalen Dialogs zu erreichen ohne eben einen modalen Dialog anzuzeigen.



  • Habe mich für SetParent entscheiden. 😉
    Meiner Meinung nach sauberer als modaler Dialog vor Anwendung (der nicht sichtbar wäre). Danach mit SetWindowLong und SetWindowPos in meinem Fenster positioniert. 😃
    Vielen Dank für eure Hilfe 👍

    Video zur fertigen Lösung:
    http://www.noctua-development.de-info.de/downloads/L%C3%B6sung.wmv



  • Waaaaaaaaah 😮

    Das ist jetzt der schlimmste Hack.
    Dir ist klar dass es sein kann dass das mit der nächsten 7-zip Version nimmer funktioniert?
    OK, unwahrscheinlich dass es überhaupt nimmer geht, aber ... sowas macht man halt normalerweise nicht, und daher wird von Programmen auch nicht erwartet dass sie mit sowas klarkommen.


Anmelden zum Antworten