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.