![]() |
AW: 1. Instanz nach vorn bringen, wenn 2. geöffnet wird - fensterunabhängig!
Also auf zum nächsten Versuch:
Ich werde die Pipe wieder gegen einen Mutex ersetzen, um herauszubekommen, ob die aktuelle Instanz die einzige ist. Die Pipe ist, so wie ich sie momentan im Code habe, sowieso ziemlich zweckentfremdet. Wenn ich nun eine weitere Instanz finde (= der Mutex bereits reserviert/in Benutzung ist), dann sende ich mit BroadcastSystemMessage eine Message an alle Applications, die ein Antwort-Handle enthält. Die 1. Instanz reagiert darauf und schickt eine Message an das Antworthandle, welches die Prozess-ID enthält. Der Rest läuft dann wie bisher. Vielleicht finde ich auch noch Optimierungspotenzial - habe da eine Option BSF_ALLOWSFW gesehen. Ich poste auf alle Fälle den finalen Code hier. @ASM: Danke für die Idee mit den Broadcast-Messages! @CCRDude: Das sind gute Hinweise, die du da bringst. In meinem Fall geht es allerdings nicht um das Öffnen von Dateien, sondern um ein reines Arbeitswerkzeug, das mit Daten aus einer Datenbank versorgt wird. Wenn dieses Programm mit dem selben Rechnernamen mehrfach ausgeführt wird, dann kommt die Organisation in diversen Tabellen durcheinander. Außerdem wird das Programm nur firmenintern eingesetzt, und da kann man schon einige Annahmen über den Einsatz machen ;-) Zumindest soweit, dass man keine Klimmzüge macht, um Fälle abzudecken, die sowieso nicht vorkommen werden. Der Admin wird sich z.B. nie im Remotezugriff auf einem Rechner selbst (zusätzlich) einloggen und dort dieses Programm starten. Bei Programmen, die die Firma verlassen würden, müsste man deine Hinweise natürlich beachten, keine Frage! |
AW: 1. Instanz nach vorn bringen, wenn 2. geöffnet wird - fensterunabhängig!
Sidenote: Du kannst dir ja mal die
![]() ![]() |
AW: 1. Instanz nach vorn bringen, wenn 2. geöffnet wird - fensterunabhängig!
@Uwe Raabe: Könntest du mir noch einen Hinweis geben, was genau ich mir dort ansehen sollte? Bei einem groben Überfliegen ist mir noch nichts speziell aufgefallen.
|
AW: 1. Instanz nach vorn bringen, wenn 2. geöffnet wird - fensterunabhängig!
Es klappt! Endlich! Folgender Code hat gewonnen:
Delphi-Quellcode:
const
ProgUID = 'geheim :-p'; BSF_ALLOWSFW = $00000080; // fehlt in Unit Windows neben z.B. BSF_QUERY var s: string; HMutex: THandle = 0; PBroadcastRecipients: PDWORD; WM_CCCSingleInstanceBroadcast: UINT = 0; function TIrgendeineKlasse.SingleInstanceBroadcastReceiver(var m: TMessage): Boolean; // muss zwecks Akzeptanz durch Application.HookMainWindow als Methode einer Klasse implementiert sein begin Result := False; if m.Msg = WM_CCCSingleInstanceBroadcast then Application.BringToFront; end; initialization WM_CCCSingleInstanceBroadcast := RegisterWindowMessage(ProgUID); // eindeutige Message-ID holen HMutex := CreateMutex(nil, True, ProgUID); if (HMutex = 0) or (GetLastError = ERROR_ALREADY_EXISTS) or (GetLastError = ERROR_ACCESS_DENIED) then begin // dieser Code läuft nur in der 2. Instanz des Programms New(PBroadcastRecipients); try PBroadcastRecipients^ := BSM_APPLICATIONS; BroadcastSystemMessage(BSF_ALLOWSFW or BSF_IGNORECURRENTTASK or BSF_POSTMESSAGE, PBroadcastRecipients, WM_CCCSingleInstanceBroadcast, 0, 0); // an alle: hier ist noch einer SwitchToThread; // Rest der Zeitscheibe verwerfen, damit die Instanz sich nach vorn bringen kann (falls das durch Race-Condition nicht klappt: Pech gehabt) finally Dispose(PBroadcastRecipients); end; MessageBox(0, 'Das Programm läuft bereits', '', MB_SYSTEMMODAL or MB_SETFOREGROUND or MB_TOPMOST); // über die erste Instanz legen Halt; end; Application.HookMainWindow(TIrgendeineKlasse.SingleInstanceBroadcastReceiver); // Klassenmethode sollte gehen - dieser Teil ist bei mir ganz anders umgesetzt finalization if HMutex > 0 then CloseHandle(HMutex); end. |
AW: 1. Instanz nach vorn bringen, wenn 2. geöffnet wird - fensterunabhängig!
Zitat:
|
AW: 1. Instanz nach vorn bringen, wenn 2. geöffnet wird - fensterunabhängig!
Zitat:
Dieser Code funktioniert hier allerdings ganz gut:
Delphi-Quellcode:
Ich würde allerdings trotzdem den Mutex als Sentinel verwenden, und die Indizierung auf 0 in den Listen muss auch nicht immer richtig sein.
uses
madKernel; procedure CheckFirstInstance; var prcs: IProcesses; begin prcs := Processes(CurrentProcess.ExeFile); if prcs.ItemCount > 1 then begin prcs[0].Windows_[0].BringToForeground(); Halt; end; end; initialization CheckFirstInstance; end. Der Knackpunkt ist hier, daß die zweite Instanz hier die erste in den Vordergrund bringt und nicht die erste sich selbst. Das Privileg, das ForegroundWindow zu ändern hat nämlich nicht jeder. Der gerade im Vordergrund liegende Prozess allerdings schon. |
AW: 1. Instanz nach vorn bringen, wenn 2. geöffnet wird - fensterunabhängig!
@Uwe Raabe: Ich war davon ausgegangen, dass das während der Verarbeitung der Message mit BSF_ALLOWSFW erlaubt sei, denn genau so ist diese Option definiert. Damit ist sie also komplett sinnfrei. Darf ich fragen, auf welcher Windows-Version du getestet hast? Bei mir läuft es unter Win7 32bit und 64bit gleichermaßen wie gewünscht.
Ich werde also nochmals umbauen (never ending story...) und der zweiten Instanz antworten, welches Fenster sie in den Vordergrund holen soll. |
AW: 1. Instanz nach vorn bringen, wenn 2. geöffnet wird - fensterunabhängig!
Letzter Stand (2. Instanz bringt die erste nach vorn):
Delphi-Quellcode:
Mann, ist das viel Code geworden, aber letztlich steckt ja gar nicht so viel dahinter...
const
ProgUID = 'geheim :-p'; WM_AnswerToSecondInstance = WM_USER + 1; var HMutex: THandle = 0; PBroadcastRecipients: PDWORD; WM_CCCSingleInstanceBroadcast: UINT = 0; function TIrgendeineKlasse.SingleInstanceBroadcastReceiver(var m: TMessage): Boolean; // muss zwecks Akzeptanz durch Application.HookMainWindow als Methode einer Klasse implementiert sein var LHandle: HWnd; TopWindow: HWnd; begin Result := False; if m.Msg = WM_CCCSingleInstanceBroadcast then begin // Logic copied from Application.BringToFront if Application.MainFormOnTaskBar and (Application.MainForm <> nil) then LHandle := Application.MainForm.Handle else LHandle := Application.Handle; if LHandle <> 0 then begin TopWindow := GetLastActivePopup(LHandle); if (TopWindow <> 0) and (TopWindow <> Application.Handle) and IsWindowVisible(TopWindow) and IsWindowEnabled(TopWindow) then PostMessage(m.WParam, m.LParam, TopWindow, 0); end; end; end; function TIrgendeineKlasse.SecondInstanceReceiver(var m: TMessage): Boolean; // muss zwecks Akzeptanz durch Application.HookMainWindow als Methode einer Klasse implementiert sein begin Result := False; case m.Msg of WM_AnswerToSecondInstance: SetForegroundWindow(m.WParam); end; end; initialization WM_CCCSingleInstanceBroadcast := RegisterWindowMessage(ProgUID); // eindeutige Message-ID holen HMutex := CreateMutex(nil, True, ProgUID); if (HMutex = 0) or (GetLastError = ERROR_ALREADY_EXISTS) or (GetLastError = ERROR_ACCESS_DENIED) then begin // dieser Code läuft nur in der 2. Instanz des Programms Application.HookMainWindow(TIrgendeineKlasse.SecondInstanceReceiver); // Klassenmethode sollte gehen - dieser Teil ist bei mir ganz anders umgesetzt New(PBroadcastRecipients); try PBroadcastRecipients^ := BSM_APPLICATIONS; BroadcastSystemMessage(BSF_IGNORECURRENTTASK, PBroadcastRecipients, WM_CCCSingleInstanceBroadcast, MessageDistributor.Handle, WM_AnswerToSecondInstance); // an alle: hier ist noch einer finally Dispose(PBroadcastRecipients); end; SwitchToThread; // Rest der Zeitscheibe verwerfen, damit die 1. Instanz antworten kann (falls das durch Race-Condition nicht klappt: Pech gehabt) Application.ProcessMessages; // Antwort verarbeiten MessageBox(0, 'Das Programm läuft bereits', '', MB_SYSTEMMODAL or MB_SETFOREGROUND or MB_TOPMOST); // über die erste Instanz legen Halt; end; Application.HookMainWindow(TIrgendeineKlasse.SingleInstanceBroadcastReceiver); // Klassenmethode sollte gehen - dieser Teil ist bei mir ganz anders umgesetzt finalization if HMutex > 0 then CloseHandle(HMutex); end. |
AW: 1. Instanz nach vorn bringen, wenn 2. geöffnet wird - fensterunabhängig!
Zitat:
- neue VCL-Anwendung - deinen Code in die Unit aufgenommen - noch 'ne Dummy-Klasse mit der entsprechenden Klassenmethode dazu - compiliert - aus dem Explorer 1. Instanz gestartet - Delphi aktiviert (1. Instanz verliert den Focus und wird verdeckt) - aus dem Explorer die 2. Instanz gestartet exp: 1. Instanz kommt nach vorn act: 1. Instanz bleibt verdeckt, aber Taskbar-Icon blinkt |
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:44 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz