Einzelnen Beitrag anzeigen

RSE

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

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

  Alt 5. Mär 2013, 15:39
Fast geschafft... Fast! Hier ist mein Code:
Delphi-Quellcode:
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.
Ich habe mein Bestes gegeben, Google und MSDN gelesen, aber an den 3 Punkten oben, die mit ##### gekennzeichnet sind, komme ich nicht weiter.
  • Punkt1: In keinem der untersuchten Threads gibt es ein aktives Fenster. Der Thread, in dem die 1. Instanz zum Testzeitpunkt definitiv ein Fenster anzeigt, ist dabei der zuerst durchsuchte Thread - hier müsste also ein Handle eingetragen sein, wenn ich MSDN richtig verstanden habe. Zitat: "A handle to the active window within the thread." - offenbar aber doch nur für den fall, dass dieses Fenster gerade das eine im System aktive Fenster ist, das den Eingabefokus besitzt. Was gibt es für Alternativen, um an ein sichtbares oder minimiertes Fenster des Prozesses zu kommen?
  • Punkt2: Nach meinem Wissen gibt es 2 Threads in meinem Programm: Den Delphi-Hauptthread und einen von mir erstellten LogThread. Weitere Threads könnten z.B. im Hintergrund von irgendwelchen (DB)Komponenten erstellt worden sein. Warum aber plötzlich die Parameter nicht mehr stimmen sollen, ist mir schleierhaft.
  • Punkt3: Ich wäre davon ausgegangen, dass die Pipe wieder frei ist, wenn die Verbindung durch das Freigeben des Handles beendet wurde. Was muss ich tun, um die Pipe wieder freizumachen?
"Seit er seinen neuen Computer hat, löst er alle seine Probleme, die er vorher nicht hatte."

Geändert von RSE ( 5. Mär 2013 um 15:47 Uhr)
  Mit Zitat antworten Zitat