Entwickler-Ecke

Windows API - Aktives Programm ermitteln


Knodelpa - Mi 15.12.04 16:11
Titel: Aktives Programm ermitteln
Hallo,
wie kann ich ermitteln welches Programm im Vordergrund ist, demnach den Focus hat :?:

Vielen Dank
Gruß Paul


Moderiert von user profile iconKlabautermann: Topic aus CLX / Delphi Language (Object-Pascal) verschoben am Do 16.12.2004 um 12:52


Sprint - Mi 15.12.04 23:43

Suche im MSDN GETACTIVEWINDOW
Suche im MSDN GETFOREGROUNDWINDOW
Suche im MSDN GETFOCUS


Knodelpa - Do 16.12.04 11:26

Danke Sprint,
sobald ich dazu komme probiere ich es aus. Ich habe noch eine Frage:
Wie bekomme ich Infos wie das Fenster, bzw. das Programm heisst. Hast
du vielleicht ein Beispiel ? Wäre toll :-)

Viele Grüße
Paul


Sprint - Do 16.12.04 13:03

Knodelpa hat folgendes geschrieben:
Wie bekomme ich Infos wie das Fenster, bzw. das Programm heisst. Hast
du vielleicht ein Beispiel?

Du holst dir mit GetForegroundWindow das Fensterhandle, das gerade aktiv ist. Mit GetWindowThreadProcessId ermittelst du den Prozess, der das Fenster erstellt hat.
Jetzt hast du schon mal die ProcessId. Du kannst nun mit OpenProcess und GetModuleFileNameEx auf Win2k & XP Rechnern den vollständigen Namen ermitteln.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
const
  S_MSG = 'Fenster: %d' + #13#10 + 'Titel: %s' + #13#10 + 'Dateiname: %s';
var
  AppHWnd: HWND;
  Title: String;
  ProcessId: DWORD;
  ProcessHandle: THandle;
  FileName: String;
begin

  // Fenster ermitteln das im Vordergrund liegt
  AppHWnd := GetForegroundWindow;

  if IsWindow(AppHWnd) then
  begin
    // Fenstertext auslesen
    SetLength(Title, GetWindowTextLength(AppHWnd) + 1);
    SetLength(Title, GetWindowText(AppHWnd, PChar(Title), Length(Title)));

    // Prozess ermitteln, der das Vordergrundfenster erstellt hat
    if GetWindowThreadProcessId(AppHWnd, ProcessId) <> 0 then
      if ProcessId <> 0 then
      begin
        ProcessHandle := OpenProcess(PROCESS_VM_READ or PROCESS_QUERY_INFORMATION, False, ProcessId);
        if ProcessHandle <> 0 then
        begin
          SetLength(FileName, MAX_PATH + 1);
          SetLength(FileName, GetModuleFileNameEx(ProcessHandle, 0, PChar(FileName), Length(FileName)));
          CloseHandle(ProcessHandle);
        end;
      end;
  end;

  ShowMessage(Format(S_MSG, [AppHWnd, Title, FileName]));


Das Problem ist nur, das du genügend Rechte haben muss, um ein ProcessHandle zu bekommen. Das bedeutet, dass das kein 100%ig sicherer Weg ist. Sollte auch nur ein Beispiel sein.
Auf Win9x Rechnern würde ich CreateToolhelp32Snapshot, Process32First & Process32Next nutzen.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
const
  S_MSG = 'Fenster: %d' + #13#10 + 'Titel: %s' + #13#10 + 'Dateiname: %s';
var
  AppHWnd: HWND;
  Title: String;
  ProcessId: DWORD;
  ProcessSnap: THandle;
  ProcessEntry: TProcessEntry32;
  FileName: String;
begin

  // Fenster ermitteln das im Vordergrund liegt
  AppHWnd := GetForegroundWindow;

  if IsWindow(AppHWnd) then
  begin
    // Fenstertext auslesen
    SetLength(Title, GetWindowTextLength(AppHWnd) + 1);
    SetLength(Title, GetWindowText(AppHWnd, PChar(Title), Length(Title)));

    // Prozess ermitteln, der das Vordergrundfenster erstellt hat
    if GetWindowThreadProcessId(AppHWnd, ProcessId) <> 0 then
      if ProcessId <> 0 then
      begin
        ProcessSnap := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
        if ProcessSnap <> INVALID_HANDLE_VALUE then
        begin
          ProcessEntry.dwSize := SizeOf(TProcessEntry32);
          if Process32First(ProcessSnap, ProcessEntry) then
          begin
            repeat
              if ProcessId = ProcessEntry.th32ProcessID then
              begin
                FileName := ProcessEntry.szExeFile;
                Break;
              end;
            until (not Process32Next(ProcessSnap, ProcessEntry));
          end;
          CloseHandle(ProcessSnap);
        end;
      end;
  end;

  ShowMessage(Format(S_MSG, [AppHWnd, Title, FileName]));


Das Beispiel kannst du zwar auch unter Win2k & WinXP benutzen, aber szExeFile beinhaltet nur den Namen der Datei. Unter Win9x steht dort der vollständige Pfad mit Dateinamen drin.


Knodelpa - Fr 17.12.04 17:56

Hallo Sprint,

das Programm lässt sich bei mir (Delphi5) nicht compilieren !!??

GetWindowThreadProcessId(AppHWnd, ProcessId)

führt zu Fehler

[Fehler] Unit1.pas(51): Inkompatible Typen: 'Cardinal' und 'Pointer' :?: :?:

Kannst du mir noch mal helfen oder das komplette Programm schicken ??

Gruß Paul


Sprint - Fr 17.12.04 18:02

Knodelpa hat folgendes geschrieben:
[Fehler] Unit1.pas(51): Inkompatible Typen: 'Cardinal' und 'Pointer'


Dann musst du...

Delphi-Quelltext
1:
GetWindowThreadProcessId(AppHWnd, ProcessId)                    


zu...

Delphi-Quelltext
1:
GetWindowThreadProcessId(AppHWnd, @ProcessId)                    


...umschreiben.


Motzi - Fr 17.12.04 18:12

@Sprint: GetWindowText/GetWindowTextLength sollte man nicht verwenden, sondern lieber direkt die WM_GETTEXT/WM_GETTEXTLENGTH-Messages schicken:
PSDK hat folgendes geschrieben:
To retrieve the text of a control in another process, send a WM_GETTEXT message directly instead of calling GetWindowText.


Sprint - Fr 17.12.04 18:24

Motzi hat folgendes geschrieben:
GetWindowText/GetWindowTextLength sollte man nicht verwenden, sondern lieber direkt die WM_GETTEXT/WM_GETTEXTLENGTH-Messages schicken

Hatte irgendwo schon mal den Hinweis gelesen. GetWindowText hat bei Form noch nie versagt bzw. ist mir bis jetzt noch nie aufgefallen. GetWindowText versagt bei Password-Edit's ab Windows 2000 total. Das muss man schon WM_GETTEXT nehmen.

Wenn du jetzt ein Beispiel für Formen hast, wo GetWindowText nicht funktioniert, dann wäre ich dafür dankbar. :)


Knodelpa - Fr 17.12.04 18:50

Hallo Sprint,

vielen Dank. Genau dies habe ich gesucht. Jetzt steht meinem Tatendrang nichts
mehr im Weg. :D :D :wink:


Knodelpa - Sa 25.12.04 20:40

Hallo Sprint,
ich brauche nochmal deine Hilfe. Da ich nicht möchte, dass mein Programm beendet werden kann habe ich das ganze in eine Serviceanwendung verpackt. Leider funktioniert dein Beispiel als Serviceanwendung nicht :-( Solange ich mich noch in der Delphi Enwicklung befinde funktioniert es noch. Als Dienst ist AppHWnd immer 0.

Ich bitte dich nochmals um Hilfe.

Gruß Paul


Sprint - Sa 25.12.04 21:21

Knodelpa hat folgendes geschrieben:
Leider funktioniert dein Beispiel als Serviceanwendung nicht

Schau mal in die Hilfe unter TService, Interactive.


Knodelpa - Sa 25.12.04 21:38

Hallo Sprint,

Volltreffer. Sieht gut aus :D :D :D