D
Hallo Zusammen.
Allgemein:
Nach etlichen Stunden der Arbeit und des testens, konnte ich nun eine Lösung ausfindig machen.
Dabei werden sämtliche Fehler in Bezug zu erstellten Unterformularen mit der Eigenschaft TOPMOST (WS_EX_TOPMOST) abgefangen und behoben.
Beschreibung - Lösung:
Um die auftretenden Eigenschaftsverluste zu eliminieren, gilt es im zu erstellenden TOPMOST-Window folgende Messages abzufangen und zu bearbeiten.
- WM_WINDOWPOSCHANGING
- WM_SHOWWINDOW
- WM_ACTIVATE
Eine ausführliche Beschreibung der abgefangenen Ereignisse und aus welchem Grund dies so gemacht wurde, ist unten ersichtlich.
Wichtig ist aber noch, dass der Formularstyle mit wsStayOnTop definiert wurde.
Kurzbeschreibung Anwendung
Um folgende Zeile zu verstehen, ist allenfalls ein kleiner Informationsteil zum Applikationsdesign notwendig.
static_cast<UnicodeString>(cWindowName).Pos(L"Pendenzenplaner:")<=0
Das Hauptformular erstellt wärend der Laufzeit (oder im Konstruktor) etliche Unterformulare (Meldefenster), welche im Titel stets mit "Pendenzenplaner:" beginnen.
Genau diese Fenster, sollten stets im Vordergrund sein.
Code - Lösung:
void __fastcall TF_MeldeForm::vfTWM_HandleMessage(TMessage& Msg)
{
//Hier werden die einkommenden Messages abgefangen, um sicherzustellen, dass sich das Fenster stets im Vordergrund befindet.
wchar_t cWindowName[20]={'\0'};
HWND hwActiveWindow;
switch (Msg.Msg)
{
//Bei WINPOSCHANGING wir das Ausblenden und der Verlust der Z-Order abgefangen.
case WM_WINDOWPOSCHANGING:
//Ermitteln des aktiven Fensters
hwActiveWindow=GetActiveWindow();
GetWindowText(hwActiveWindow,cWindowName,20);
//Erweitern des Flags um SWP_NOZORDER. Dies verhindert, dass der Parameter hwndInsertAfter beachtet wird
//und so die Eigenschaft TOPMOST verliert.
//Die Ausdrücke haben folgende Bedeutung
// 1. Anweisung muss ausgeführt werden, wenn das letzt aktive Fenster das Main-Fenster war.
// Da sonst die Eigenschaft beim Minimieren des Fensters verloren gehr.
// 2. Wenn der hwndInsertAfter nicht mehr HWND_TOP entspricht, so ist das Ändern der Eigenschaft zwingend notwendig
// 3. Die Eigenschaft darf nur angepasst werden, wenn vorhin ein Fenster der Applikation aktiv war.
// Sonst wird das Fenster beim anklicken nicht vor ein anderes Fenster der Applikation gestellt.
// -> Erst nach 2 maligem anklicken
if (hwActiveWindow==hwMainForm || (reinterpret_cast<WINDOWPOS*>(Msg.LParam)->hwndInsertAfter!=HWND_TOP && static_cast<UnicodeString>(cWindowName).Pos(L"Pendenzenplaner:")<=0))
reinterpret_cast<WINDOWPOS*>(Msg.LParam)->flags |= SWP_NOZORDER;
//Den Parameter des Ausplendens löschen (SWP_HIDEWINDOW)
//Ist nur notwendig, wenn das Fenster im Konstruktor des Hauptformulares erstellt wird.
//Denn dann erhält das Fenster neben der SHOWWINDOW-Message auch noch den oben genannten Parameter
reinterpret_cast<WINDOWPOS*>(Msg.LParam)->flags &= ~SWP_HIDEWINDOW;
break;
//Neben dem Ausplenden via WM_WINDOWPOSCHANGING muss auch SHOWWINDW abgefangen werden.
//Dabei wird der WParam auf True gesetzt, das Heisst, das Fenster wird sichtbar.
case WM_SHOWWINDOW:
Msg.WParam=true;
break;
//War zuletzt ein Fenster der Anwendung aktiv (nicht das Hauptfenster).
//So scheint der Taskbutton durch das minimieren der Anwendung ein falsches Handle zu erhalten.
// -> Beim klicken auf den Taskbutton wird das Fenster nicht mehr aktiv.
//Aus diesem Grund ist es notwendig, das Fenster selbst in den Vordergrund zu holen.
// -> Dies jedoch nur, wenn das Fenster nicht durch einen Mausklick aktiviert wird.
// -> und das Hauptfenster sichtbar ist und nicht im Tray,....
case WM_ACTIVATE:
if (Msg.WParam==WA_ACTIVE && IsWindowVisible(hwMainForm))
SetForegroundWindow(hwMainForm);
break;
}
//Weiterverarbeiten der Message
OldWndProc(Msg);
}
Vielleicht hat jemand ja das selbe Problem und hoffe, dass Ihm mit dieser Lösungsvariante geholfen werden konnte.
Sollten noch Fragen oder Anmerkungen auftreten, so werde ich mich bemühen, diese bestmöglich zu klären.