AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Win32/Win64 API (native code) Delphi 1. Instanz nach vorn bringen, wenn 2. geöffnet wird - fensterunabhängig!
Thema durchsuchen
Ansicht
Themen-Optionen

1. Instanz nach vorn bringen, wenn 2. geöffnet wird - fensterunabhängig!

Ein Thema von RSE · begonnen am 4. Mär 2013 · letzter Beitrag vom 6. Mär 2013
Antwort Antwort
Seite 2 von 2     12   
RSE

Registriert seit: 26. Mär 2010
254 Beiträge
 
Delphi XE Enterprise
 
#11

AW: 1. Instanz nach vorn bringen, wenn 2. geöffnet wird - fensterunabhängig!

  Alt 6. Mär 2013, 09:31
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!
"Seit er seinen neuen Computer hat, löst er alle seine Probleme, die er vorher nicht hatte."
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe
Online

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.009 Beiträge
 
Delphi 12 Athens
 
#12

AW: 1. Instanz nach vorn bringen, wenn 2. geöffnet wird - fensterunabhängig!

  Alt 6. Mär 2013, 09:49
Sidenote: Du kannst dir ja mal die madCollection und dort die Processes ansehen. Macht die Sache leichter.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
RSE

Registriert seit: 26. Mär 2010
254 Beiträge
 
Delphi XE Enterprise
 
#13

AW: 1. Instanz nach vorn bringen, wenn 2. geöffnet wird - fensterunabhängig!

  Alt 6. Mär 2013, 10:47
@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.
"Seit er seinen neuen Computer hat, löst er alle seine Probleme, die er vorher nicht hatte."
  Mit Zitat antworten Zitat
RSE

Registriert seit: 26. Mär 2010
254 Beiträge
 
Delphi XE Enterprise
 
#14

AW: 1. Instanz nach vorn bringen, wenn 2. geöffnet wird - fensterunabhängig!

  Alt 6. Mär 2013, 12:20
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.
"Seit er seinen neuen Computer hat, löst er alle seine Probleme, die er vorher nicht hatte."
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe
Online

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.009 Beiträge
 
Delphi 12 Athens
 
#15

AW: 1. Instanz nach vorn bringen, wenn 2. geöffnet wird - fensterunabhängig!

  Alt 6. Mär 2013, 12:31
@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.
Nichts Spezielles - es macht lediglich das Arbeiten mit den Kernel-Objekten leichter.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe
Online

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.009 Beiträge
 
Delphi 12 Athens
 
#16

AW: 1. Instanz nach vorn bringen, wenn 2. geöffnet wird - fensterunabhängig!

  Alt 6. Mär 2013, 12:41
Es klappt!
Hier nicht! Die Instanz kommt nicht in den Vordergrund - es blinkt lediglich das Taskbar-Icon.

Dieser Code funktioniert hier allerdings ganz gut:

Delphi-Quellcode:
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.
Ich würde allerdings trotzdem den Mutex als Sentinel verwenden, und die Indizierung auf 0 in den Listen muss auch nicht immer richtig sein.

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.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
RSE

Registriert seit: 26. Mär 2010
254 Beiträge
 
Delphi XE Enterprise
 
#17

AW: 1. Instanz nach vorn bringen, wenn 2. geöffnet wird - fensterunabhängig!

  Alt 6. Mär 2013, 14:20
@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.
"Seit er seinen neuen Computer hat, löst er alle seine Probleme, die er vorher nicht hatte."
  Mit Zitat antworten Zitat
RSE

Registriert seit: 26. Mär 2010
254 Beiträge
 
Delphi XE Enterprise
 
#18

AW: 1. Instanz nach vorn bringen, wenn 2. geöffnet wird - fensterunabhängig!

  Alt 6. Mär 2013, 15:11
Letzter Stand (2. Instanz bringt die erste nach vorn):
Delphi-Quellcode:
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.
Mann, ist das viel Code geworden, aber letztlich steckt ja gar nicht so viel dahinter...
"Seit er seinen neuen Computer hat, löst er alle seine Probleme, die er vorher nicht hatte."
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe
Online

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.009 Beiträge
 
Delphi 12 Athens
 
#19

AW: 1. Instanz nach vorn bringen, wenn 2. geöffnet wird - fensterunabhängig!

  Alt 6. Mär 2013, 15:55
@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.
Win7 x64 - ganz einfach getestet:

- 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
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 2     12   


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:51 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz