![]() |
1. Instanz nach vorn bringen, wenn 2. geöffnet wird - fensterunabhängig!
Hallo,
unser Programm darf nur 1x geöffnet werden. Dazu verwenden wir ein benanntes Mutex-Objekt (Win32-API-Call CreateMutex). Für den Fall, dass ich von GetLastError = ERROR_ALREADY_EXISTS zurückbekomme, möchte ich gerne die erste Instanz des Programms nach vorne holen - unabhängig davon, was da gerade für Fenster offen sind. Allerdings scheitere ich schon daran, die Prozess-ID oder irgendetwas anderes von dem Prozess, der das Mutex-Objekt besitzt (also die erste Instanz des Programms), herauszubekommen. Der Grund ist einfach meine Unkenntnis der Win-API. Wahrscheinlich verwende ich nicht die richtigen Suchbegriffe. Ich möchte nicht nach einem Fenster mit einem bestimmten Caption suchen, dann würde ich es lieber lassen. Allerdings bin ich mir sicher, dass es durchaus elegantere Wege gibt als diesen. |
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!
Fenster kann man nicht nur anhand der Caption, sondern auch anhand des Klassennamens suchen, das ist schon deutlich eindeutiger.
Ansonsten: ne Pipe? Darüber können ggfls. auch gleich Parameter übermittelt werden (etwa wenn die zweite Instanz mit nem Dateinamen zum Öffnen als Parameter gestartet wird - soll dann ja die erste Instanz diese Datei wahrscheinlich öffnen), und die erste Instanz kann sich einfach selbst wieder in den Vordergrund holen. |
AW: 1. Instanz nach vorn bringen, wenn 2. geöffnet wird - fensterunabhängig!
@mjustin:
TJclAppInstances war prinzipiell eine gute Idee zum Nachforsten, aber ich steige da überhaupt nicht durch. Da wird irgendetwas mit File Mapping gemacht - kenne ich bisher nicht, scheint aber eine gemeinsame Datei vorauszusetzen, die von mehreren Prozessen gleichzeitig benutzt wird und in der dann Informationen gesammelt werden. Das Ganze erscheint mir zu aufwendig für meinen Einsatzzweck. @CCRDude: Von Pipes habe ich bisher auch nichts gewusst, aber folgendes scheint ein einfacher und zielführender Weg zu sein: Bei Programmstart versuche ich eine Pipe mit dem Parameter FILE_FLAG_FIRST_PIPE_INSTANCE zu erstellen. Gelingt das, so ist es die erste Programminstanz. Schlägt das fehl, so verbinde ich zu der bestehenden Pipe und informiere die erste Instanz, dass sie sich nach vorn bringen soll (Application.BringToFront) und beende die aktuelle (zweite) Instanz. Ich werde mich morgen mit dem Handling der Pipes genauer auseinandersetzen, habe jetzt nur überflogen, was Pipes sind ;-) Wenn dabei für mich unlösbare Probleme auftreten, melde ich mich nochmal, ansonsten: Danke für die Lösung! |
AW: 1. Instanz nach vorn bringen, wenn 2. geöffnet wird - fensterunabhängig!
Der Ansatz, daß sich die erste Instanz selbst in den Vordergrund bringt, wird in den meisten Fällen schief gehen. Windows erlaubt es nämlich i.A. nicht, daß ein Prozess sich selbst in den Vordergrund drängelt (da könnte ja jeder kommen). Dies ist unter anderem aber dem Prozess erlaubt, der gerade gestartet wurde - also der zweiten Instanz. Ich empfehle daher, das so zu implementieren, daß doch die zweite Instanz die erste in den Vordergrund holt.
|
AW: 1. Instanz nach vorn bringen, wenn 2. geöffnet wird - fensterunabhängig!
Also das mit den Pipes habe ich jetzt implementiert. Selbst ohne Kommunikation durch die Pipes kann ich folgendes erreichen:
Ich sehe folgende Probleme incl. Lösungen bei meinem Ansatz:
So, jetzt habe ich euch erstmal mit aktuellen Infos versorgt und werde mittagessen gehen. Wenn bis danach keine Einwände gegen das Vorgehen gepostet wurden, werde ich die Umsetzung dann angehen ;-) Mahlzeit! |
AW: 1. Instanz nach vorn bringen, wenn 2. geöffnet wird - fensterunabhängig!
Fast geschafft... Fast! Hier ist mein Code:
Delphi-Quellcode:
Ich habe mein Bestes gegeben, Google und MSDN gelesen, aber an den 3 Punkten oben, die mit ##### gekennzeichnet sind, komme ich nicht weiter.
var
PID: ULONG; // Process-ID von 1. Instanz HPipe: THandle = INVALID_HANDLE_VALUE; // wird für Server (= 1. Instanz, CreateNamedPipe) und für Client (= 2. Instanz, CreateFile) verwendet HSnap: THandle = INVALID_HANDLE_VALUE; ThreadEntry: TThreadEntry32; // aus Unit TlHelp32 GUIThreadInfo: TGUIThreadInfo; function GetNamedPipeServerProcessId(hNamedPipe: THandle; out ServerProcessId: ULONG): BOOL; stdcall; external kernel32 name 'GetNamedPipeServerProcessId'; initialization HPipe := CreateNamedPipe(PipeName, PIPE_ACCESS_OUTBOUND or FILE_FLAG_FIRST_PIPE_INSTANCE, PIPE_TYPE_BYTE or PIPE_READMODE_BYTE or PIPE_WAIT, 1, 4, 4, 0, nil); // erste Pipe-Instanz erstellen if HPipe = INVALID_HANDLE_VALUE then begin // wenn Pipe bereits besteht HPipe := CreateFile(PipeName, GENERIC_READ, 0, nil, OPEN_EXISTING, 0, 0); // auf Pipe verbinden if HPipe <> INVALID_HANDLE_VALUE then begin if GetNamedPipeServerProcessId(HPipe, PID) then // Prozess-ID des Pipe-Servers erfragen (= 1. Instanz) begin FillChar(ThreadEntry, SizeOf(ThreadEntry), 0); ThreadEntry.dwSize := SizeOf(ThreadEntry); HSnap := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, PID); // Schnappschuss aller Threads erstellen if (HSnap <> INVALID_HANDLE_VALUE) and Thread32First(HSnap, ThreadEntry) then repeat // Threads durchlaufen if ThreadEntry.th32OwnerProcessID = PID then begin // wenn Thread zu Prozess der 1. Instanz gehört FillChar(GUIThreadInfo, SizeOf(GUIThreadInfo), 0); GUIThreadInfo.cbSize := SizeOf(GUIThreadInfo); // bis hierhin klappt alles wunderbar if GetGUIThreadInfo(ThreadEntry.th32ThreadID, GUIThreadInfo) then // GUIThreadInfo beschaffen begin if (GUIThreadInfo.hwndActive > 0) then begin // wenn aktives Fenster gesetzt ist - ist immer null - Warum? ##### SetForegroundWindow(GUIThreadInfo.hwndActive); // Fenster in Vordergrund holen Break; end; end else // beim 3. Durchlauf/Thread kommt ERROR_INVALID_PARAMETER - Warum? ##### ShowMessage('GetGUIThreadInfo is unsuccessful: ' + IntToStr(GetLastError)); end; until not Thread32Next(HSnap, ThreadEntry); // nächsten Thread untersuchen end; end; // wenn Verbindung zur Pipe erfolgreich, Meldung anzeigen -> aktuelle Instanz ist die 2. // wenn Verbindung zur Pipe nicht erfolgreich, dann Meldung anzeigen wenn GetLastError <> ERROR_PIPE_BUSY -> keine Meldung für die 3. Instanz, die gleichzeitig geöffnet ist if (HPipe <> INVALID_HANDLE_VALUE) or (GetLastError <> ERROR_PIPE_BUSY) then ShowMessage('Das Programm läuft bereits'); Halt; end; finalization // Pipe-Handle freigeben - Server und Client if (HPipe <> INVALID_HANDLE_VALUE) and CloseHandle(HPipe) then HPipe := INVALID_HANDLE_VALUE; // Falls es sich um Client/2. Instanz handelt, dann ist die Pipe trotzdem weiterhin besetzt (weitere/spätere Verbindungsversuche verursachen ERROR_PIPE_BUSY) - Warum? ##### end.
|
AW: 1. Instanz nach vorn bringen, wenn 2. geöffnet wird - fensterunabhängig!
Um die offenen Fragen aus meinem letzten Post zu umgehen, habe ich nun umgebaut:
Delphi-Quellcode:
Dadurch erübrigen sich 2 der 3 Punkte, aber einer bleibt bestehen:
var
PID: ULONG; // Process-ID von 1. Instanz HPipe: THandle = INVALID_HANDLE_VALUE; // wird für Server (= 1. Instanz, CreateNamedPipe) und für Client (= 2. Instanz, CreateFile) verwendet function GetNamedPipeServerProcessId(hNamedPipe: THandle; out ServerProcessId: ULONG): BOOL; stdcall; external kernel32 name 'GetNamedPipeServerProcessId'; function EnumWindowsProcCallback(HWnd: THandle; PID: LPARAM): BOOL; stdcall; var WinPID: DWORD; begin GetWindowThreadProcessId(HWnd, WinPID); Result := WinPID <> (PULONG(PID))^; if not Result then SetForegroundWindow(HWnd); end; initialization HPipe := CreateNamedPipe(PipeName, PIPE_ACCESS_OUTBOUND or FILE_FLAG_FIRST_PIPE_INSTANCE, PIPE_TYPE_BYTE or PIPE_READMODE_BYTE or PIPE_WAIT, 1, 4, 4, 0, nil); // erste Pipe-Instanz erstellen if HPipe = INVALID_HANDLE_VALUE then begin // wenn Pipe bereits besteht HPipe := CreateFile(PipeName, GENERIC_READ, 0, nil, OPEN_EXISTING, 0, 0); // auf Pipe verbinden if HPipe <> INVALID_HANDLE_VALUE then begin if GetNamedPipeServerProcessId(HPipe, PID) then // Prozess-ID des Pipe-Servers erfragen (= 1. Instanz) EnumWindows(@EnumWindowsProcCallback, LPARAM(@PID)); // Fenster durchforsten end; // wenn Verbindung zur Pipe erfolgreich, Meldung anzeigen -> aktuelle Instanz ist die 2. // wenn Verbindung zur Pipe nicht erfolgreich, dann Meldung anzeigen wenn GetLastError <> ERROR_PIPE_BUSY -> keine Meldung für die 3. Instanz, die gleichzeitig geöffnet ist if (HPipe <> INVALID_HANDLE_VALUE) or (GetLastError <> ERROR_PIPE_BUSY) then MessageBox(0, 'Das Programm läuft bereits', '', MB_SYSTEMMODAL or MB_SETFOREGROUND or MB_TOPMOST); Halt; end; finalization // Pipe-Handle freigeben - Server und Client if (HPipe <> INVALID_HANDLE_VALUE) and CloseHandle(HPipe) then HPipe := INVALID_HANDLE_VALUE; // Falls es sich um Client/2. Instanz handelt, dann ist die Pipe trotzdem weiterhin besetzt (weitere/spätere Verbindungsversuche verursachen ERROR_PIPE_BUSY) - Warum? ##### end. Zitat:
|
AW: 1. Instanz nach vorn bringen, wenn 2. geöffnet wird - fensterunabhängig!
Anstelle mit Hilfe von Pipes lässt sich das Problem auch grundsätzlich anders lösen:
Man kann in den diversen Formfenstern des Programms individuelle Hooks der jeweiligen WndProc setzen. Dann ist es möglich, dort die beim Start der 2.Instanz abgesetzte HWND_BROADCAST-Message abzufangen und geeignet zu behandeln: // in der MainForm:
Delphi-Quellcode:
// in jeder einzelnen Form-Unit (hier exemplarisch "FormX"):
Interface
const // z.B. mit GUI-Code zweifelsfrei individualisieren UniqueAppTitle = 'MyApp#21218E21-EF54-45D9-AAA0-8F4E7455D5AE'; var UniqueAppMsg: DWord; Implementation {...} initialization UniqueAppMsg := RegisterWindowMessage(pChar(UniqueAppTitle)); end.
Delphi-Quellcode:
// im Projektfile:
Implementation
uses Mainunit; // unit der Mainform var OriginalWndProc: Pointer; CurrentFormHandle: hWnd; function FormX_HookedWndProc(FormHandle: hWnd; MessageID: LongInt; ParamW: LongInt; ParamL: LongInt): LongInt stdcall; begin if MessageID = UniqueAppMsg then begin SendMessage(Application.Handle, WM_SYSCOMMAND, SC_RESTORE, 0); SetForegroundWindow(Application.Handle); SendMessage(CurrentFormHandle, WM_SYSCOMMAND, SC_RESTORE, 0); Result := 0; end else Result := CallWindowProc(OriginalWndProc, FormHandle, MessageID, ParamW, ParamL); end; procedure TFormX.FormCreate(Sender: TObject); begin CurrentFormHandle:=FormX.Handle; OriginalWndProc := Pointer(SetWindowLong(CurrentFormHandle, GWL_WNDPROC, LongInt(@FormX_HookedWndProc))); end; procedure TFormX.FormDestroy(Sender: TObject); begin SetWindowLong(CurrentFormHandle, GWL_WNDPROC, LongInt(OriginalWndProc)); end;
Delphi-Quellcode:
Uses Windows, ...;
var Mutex: THandle; begin Mutex := CreateMutex(nil, True, UniqueAppTitle); if (Mutex = 0) or (GetLastError = ERROR_ALREADY_EXISTS) then begin SendMessage(HWND_BROADCAST, UniqueAppMsg, 0, 0); Halt(0); end else try Application.Initialize; {...} finally if Mutex <> 0 then CloseHandle(Mutex); end; |
AW: 1. Instanz nach vorn bringen, wenn 2. geöffnet wird - fensterunabhängig!
@ASM: Uwe Raabe hat dazu oben etwas wichtiges gesagt: evtl. kann sich ein Programm gar nicht selber in den Vordergrund holen (ich mache das auch nicht so, dachte nur, dass das noch praktischer wäre, deswegen schrieb ich das als Vorschlag).
Aus eigener Erfahrung möchte ich noch ein paar wichtige Sachen ergänzen: Fast User Switching und Terminal Services / Remote-Desktop-Zugriff ermöglichen es, dass theoretisch verschiedene Benutzer (oder verschiedene Instanzen desselben Benutzers ein Programm auf demselben Rechner nutzen wollen. Wäre blöd, wenn Benutzer A ein Dokument öffnen will und es bei Benutzer B aufgeht, weil der die erste Instanz offen hat. Deswegen reicht ein UniqueAppTitle wie von ASM beschrieben auf keinen Fall aus! Session-ID und Username gehören da mit rein. Am besten noch den Namen des Desktops. Zusätzlich könnte der Prefix Local\ helfen, um das Mutex definitiv innerhalb der Session zu erzeugen (kommt halt drauf an, wofür man es will). Steht alles in der Hilfe zu ![]() Gleiches gilt natürlich auch für den Namen der Pipe - sicherstellen, dass da keine Übergriffe stattfinden können! Negativbeispiel: Adobe Reader (über mehrere Versionen, nicht sicher ob noch in aktueller). Admin A startet den Adobe Reader, um ein PDF zu lesen. DAU D, ein eingeschränkter Benutzeraccount, surft im Netz und öffnet im Browser ein PDF. Das Adobe Reader-Plugin ist so "intelligent", sich an den von A gestarteten Reader anzuflanschen. Jetzt hat D über die Öffnen-Funktion vollen Administrator-Zugriff. Und wenn das Programm u.U. auch elevated sein kann, muss man planen, wie man damit umgeht, weil der BROADCAST u.U. nicht in beide Richtungen funktioniert (Programm, die elevated sind, sollen ja eben nicht per Window Messages von nicht elevateten Programmen "gesteuert" werden können). |
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 07:56 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