Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Eigenes Handle finden (https://www.delphipraxis.net/141221-eigenes-handle-finden.html)

Schwedenbitter 5. Okt 2009 10:10


Eigenes Handle finden
 
Hallo,

ich habe folgendes Problem:
Ich habe eine Anwendung nonVCL geschrieben. Nun benötige ich u.a. für den Aufruf von GetWindow(); das Handle meines eigenen Programms. Wenn ich VCL benutze, dann nehme ich dort entweder Application.Handle oder abgeleitet vom Haupt-Formular self.Handle. Das geht hier leider nicht.

Wie komme ich möglichst ohne großen Aufwand an mein Handle ran?

Gruß, Alex

P.S. Auch wenn die Lösung einfach sein sollte und schon 100fach im Forum steht, bitte nicht meckern. Ich habe schon mehrmals die Suche benutzt, aber nichts gefunden. U.U. liegt es auch an falschen/fehlenden Suchbegriffen.

Fridolin Walther 5. Okt 2009 10:18

Re: Eigenes Handle finden
 
Wenn Du via MSDN-Library durchsuchenGetWindow das Handle eines Deiner eigenen Fenster ermitteln möchtest, solltest Du das Fensterhandle ja haben (immerhin wurde es bei der Fenstererstellung ja zurückgeliefert und Du hast es hoffentlich gespeichert).

Schwedenbitter 5. Okt 2009 13:00

Re: Eigenes Handle finden
 
Zitat:

Zitat von Fridolin Walther
Wenn Du via MSDN-Library durchsuchenGetWindow das Handle eines Deiner eigenen Fenster ermitteln möchtest, solltest Du das Fensterhandle ja haben (immerhin wurde es bei der Fenstererstellung ja zurückgeliefert und Du hast es hoffentlich gespeichert).

Ich kann damit nichts anfangen. Kannst Du das bitte genauer erläutern? Wenn ich mein Fensterhandle hätte, müsste ich das nicht mit GetWindow erst suchen.
Entschuldigung: Evtl. habe ich mich auch nicht vollständig/richtig ausgdrückt. Meine Anwendung hat kein(e) Fenster. Sie läuft einem Dienst ähnlich ohne Benutzerinteraktion im Hintergrund. Dabei ist es notwending, dass ich auf das Ende eines bestimmten Programms/Fensters warte (vgl. diesen Thread). Um das zu prüfen, wollte ich mit GetWindow alle Fenster so durchsuchen:
Delphi-Quellcode:
function FindWindowByTitle(WindowTitle: string): Hwnd;
var
  NextHandle: Hwnd;
  NextTitle: array[0..255] of char;
begin
  // Get the first window
  NextHandle := GetWindow(Application.Handle, GW_HWNDFIRST);
  while NextHandle > 0 do
  begin
    // retrieve its text
    GetWindowText(NextHandle, NextTitle, 255);
    if Pos(WindowTitle, StrPas(NextTitle)) <> 0 then
    begin
      Result := NextHandle;
      Exit;
    end
    else
      // Get the next window
      NextHandle := GetWindow(NextHandle, GW_HWNDNEXT);
  end;
  Result := 0;
end;
Mit Einbindung der VCL klappt das wunderbar. Nur wie mache ich das ohne ein Fenster? Mit GetWindow(0, GW_HWNDFIRST); klappt es jedenfalls nicht.

Gruß, Alex

Luckie 5. Okt 2009 13:11

Re: Eigenes Handle finden
 
Warum so kompliziert. lass Windows doch die Arbeit für dich machen: MSDN-Library durchsuchenFindWindow.

Schwedenbitter 5. Okt 2009 13:25

Re: Eigenes Handle finden
 
Zitat:

Zitat von Luckie
Warum so kompliziert.

Weil ich leider nicht den vollständigen Namen kenne. Die Funktion oben liefert mir aber nur ein Ergebnis, wenn ich genau diesen vollständigen Namen angeben kann. Sollte ich mich irren, wäre die Function ja in der Tat wenig sinnvoll.

Das bringt mich zu einem weiteren Problem: Mit der Function findet man ja allerhand Fenster, auch solche die nicht sichbar sind. Gibt es eine Möglichkeit gerade in MDI-Programmen auch die anderen Fenster im Programm selbst zu finden? Wenn ich z.B. Im FireFox mehrere Fenster geöffnet habe, dann zeigt er mir immer nur den Titel des aktuell angezeigten Fensters an.
Dass es grundsätzlich möglich sein muss, sehe ich an WinSpy.

Gruß, Alex

Schwedenbitter 5. Okt 2009 15:18

Re: Eigenes Handle finden
 
Bei Torry's Delphi Page habe ich das hier gefunden:
Delphi-Quellcode:
function EnumWindowsProc(wHandle: HWND; lb: TListBox): Bool; stdcall; export;
var
  Title, ClassName: array[0..255] of char;
begin
  Result := True;
  GetWindowText(wHandle, Title, 255);
  GetClassName(wHandle, ClassName, 255);
  if IsWindowVisible(wHandle) then
     lb.Items.Add(string(Title) + '-' + string(ClassName));
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  EnumWindows(@EnumWindowsProc, Integer(Listbox1));
end;
Hier wird als HWND einfach ein Zeiger auf die Function selbst verwandt. Ich habe das in meiner o.g. Procedure probiert. Es sah auf den ersten Blick ganz verlocken aus. Aber ich hatte schon vermutet, dass es nicht gehen würde, denn Handle <> Pointer. Oder kann man das wider Erwarten zum Laufen bringen mit einem Compilter-Schalter?

Weiter unten auf derselben Seite steht dann die Function GetCurrentThreadID auch im Zusammenhang mit HWND. Ich habe das probiert. Macnhmal kommen ein paar Fenstername (aber nicht alle)...

Gruß, Alex

turboPASCAL 5. Okt 2009 15:23

Re: Eigenes Handle finden
 
Zitat:

ch habe eine Anwendung nonVCL geschrieben. Nun benötige ich u.a. für den Aufruf von GetWindow(); das Handle meines eigenen Programms.
Wenn das Ding dein Programm ist hat du duch schon das Handle deines Fensters.
Ist jetzt die Frage, wie erstellts du das Fenster ?

Schwedenbitter 5. Okt 2009 15:49

Re: Eigenes Handle finden
 
Zitat:

Zitat von turboPASCAL
Wenn das Ding dein Programm ist hat du duch schon das Handle deines Fensters.
Ist jetzt die Frage, wie erstellts du das Fenster ?

Wahrscheinlich habe ich jetzt Tomaten auf den Augen.
Ich habe kein Fenster und ich erstelle auch keins. Deshalb kenne ich nicht "... das Handle deines Fensters." Wenn dem so wäre, gäbe es das Problem ja nicht.

Ich habe eine Anwendung ohne die VCL und ohne jedes Fenster. Ich möchte nur die Namen der vorhandenen Fenster mit der unter #3 genannten Function für die interne Weiterverarbeitung finden. Innerhalb dieser Function findet sich der Aufruf
Delphi-Quellcode:
NextHandle := GetWindow(Application.Handle, GW_HWNDFIRST);
wieder, der eben ein Handle voraussetzt. Da ich weder ein TForm noch ein TApplication habe, kann ich self.Handle bzw. Application.Handle nicht als Parameter mitgeben. Ich weiß nicht, wie ich mein Problem noch schildern soll.

Was gebe ich ohne Fenster als hwnd mit? bzw.
Was gibt es für Alternativen für die Funktion?

Gruß, Alex

Luckie 5. Okt 2009 15:55

Re: Eigenes Handle finden
 
MSDN-Library durchsuchenEnumWindows.

Sherlock 5. Okt 2009 15:57

Re: Eigenes Handle finden
 
Wenn Du kein Handle hast, dann kannst Du auch keines übergeben, versuchs an der Stelle mal mit nil oder so.

Sherlock

Schwedenbitter 5. Okt 2009 16:13

Re: Eigenes Handle finden
 
Zitat:

Zitat von Sherlock
Wenn Du kein Handle hast, dann kannst Du auch keines übergeben, versuchs an der Stelle mal mit nil oder so.

nil kann nicht gehen (Siehe oben). Und 0 bringt auch kein Ergebnis. Das hatte ich noch vor dem Erstellen des Thread selbst probiert.

Ich habe aber hier zufällig eine Lösung gefunden. Es wird - wenn auch in anderer Sache - einfach mit FindWindow ein temporäres Handle abgefragt und dann mit diesem die Function aufgerufen. Bis jetzt klappt das so. Wenn ich ein paar mehr Tests damit erfolgreich gemacht habe, dann wird der Thread als gelöst markiert!

@Luckie
Mit EnumWindows muss ich mich noch belesen. Die Frage war im Grunde nur am Rande und wird später noch gebraucht werden. Danke für den Tip.

Gruß, Alex

[EDIT]Also die Tests laufen Prima. :cheers: Mein Problem ist damit gelöst - die Ausgangsfrage von mir aber nicht: Denn ich kann jetzt zwar die Funktion erfolgreich aufrufen. Das Handle meiner nonVCL-Anwendung kenne ich aber immer noch nicht.[/EDIT]

turboPASCAL 5. Okt 2009 18:13

Re: Eigenes Handle finden
 
Wie ist denn deine App nun aufgebaut ?

Ein Handle bekommt diese erst wenn sie auf irgrnd eine Weise ein Fenster erstellt.


Delphi-Quellcode:
programm Noppe;

uses
  Windows;

begin
  while True do
  begin
    Time = GetTickCount;
  end;
end.
Hat zB. kein Handle, sondern nur eine Process ID.

Schwedenbitter 5. Okt 2009 20:15

Re: Eigenes Handle finden
 
Zitat:

Zitat von turboPASCAL
Wie ist denn deine App nun aufgebaut ?
Ein Handle bekommt diese erst wenn sie auf irgrnd eine Weise ein Fenster erstellt.

Dann habe ich maximal eine ProcessID. Es ist ein Programm wie zu Zeiten von TurboPascal 5 (= war das erste, mit dem ich Kontakt hatte). Ein Fenster kommt nur, wenn es einen Fehler gibt zur Information des Benutzer ohne jede Interaktion. Ohne Fehler, gibts auch kein Fenster.
Zum Ablauf: Wenn der Benutzer eine Datei bearbeiten möchte, wird diese auf seinen Rechner in ein Temp-Verzeichnis kopiert. Dort mit dem in Win verknüpften Programm geöffnet. Das Programm wird überwacht (Fenstername und Lock-Datei). Für ersteres brauchte ich ein Handle. Wenn die Datei geschlossen wird, wird geprüft, ob es Änderungen gibt und die Datei dann zurückkopiert oder verworfen. Der Sinn ist es einem lahmen VPN auf die Sprünge zu helfen, kurzfristige Netzausfälle abzupuffern und die Anzahl der über das VPN offen gehaltenen Dateien möglichst auf Null zu reduzieren.

Also müsste der Titel vom Thread wohl eher lauten: Eigenes Handle von fensterlosem Programm finden. Soll ich das - soweit noch möglich - ändern?

Gruß, Alex

Fridolin Walther 5. Okt 2009 20:34

Re: Eigenes Handle finden
 
Ohje, da läuft ja einiges an einander vorbei ...

Zuerst einmal Schwedenbitter ist es so, daß nonVCL von den meisten so aufgefasst wird, daß Du eine Anwendung mit Fenstern hast, bei der Du aber keine VCL Komponenten verwendest sondern direkt auf die Windows Fenster API zugreifst. Daher hat Dich auch jeder gefragt, wieso Du das Handle zu Deinem Fenster nicht hast, wenn Du es denn schon manuell erstellt hast. Da Du aber offensichtlich eine Anwendung hast, die keine Fenster anzeigt oder besitzt, ist die Frage recht simpel:

Wenn Du kein Fenster erstellst, hast Du auch kein Fenster Handle. Willst Du ein eigenes Fenster Handle haben, musst Du eines erstellen.

Ansonsten scheinst Du ja mit Hilfe des Fenster Handle überprüfen zu wollen, ob eine bestimmte Anwendung noch aktiv ist. Das ist um ehrlich zu sein weder sonderlich effektiv noch sicher. Aber wenn Du genau schilderst (am Besten mit exakten Anwendungsnamen) was Du möchtest, wird man Dir sicher nähere Informationen geben können.

Schwedenbitter 5. Okt 2009 23:50

Re: Eigenes Handle finden
 
Zitat:

Zitat von Fridolin Walther
Ansonsten scheinst Du ja mit Hilfe des Fenster Handle überprüfen zu wollen, ob eine bestimmte Anwendung noch aktiv ist.

Genau das ist/war mein Ziel. :lol:

Zitat:

Zitat von Fridolin Walther
Das ist um ehrlich zu sein weder sonderlich effektiv noch sicher.

Was ist effektiver und sicherer? Ich frage gerade deshalb und lerne gern dazu. Diese Behauptung aufzustellen ist leicht. Eine funktionierende Alternative anzubieten aber offenbar schwer.

Zitat:

Zitat von Fridolin Walther
Aber wenn Du genau schilderst (am Besten mit exakten Anwendungsnamen) was Du möchtest, wird man Dir sicher nähere Informationen geben können.

Das habe ich schon und niemand hatte bislang eine bessere Idee! Ich gehe jetzt schlafen. Vielleicht hat sich ja bis morgen mein Problem gelöst und jemand eine bessere Idee gepostet.

Das Problem mit dem Handle hat sich sowieso relativiert: Ich habe jetzt ein paar Fehler provoziert und festgestellt, dass meine Fehlermeldungen nicht in den Vordergrund kommen / von anderen geöffneten Fenstern verdeckt sind. Das ist schlecht, weil sie so niemand sieht und ich musste nachhelfen. Hierzu brauchte ich wiederum das vor Erstellung meines ersten Fensters nicht existente Handle meines Programms. Also habe ich mir ein Message-Only-Window erstellt und kann so dessen Handle gleich verwenden.

Wie gesagt: Ich bin für Tipps immer offen. 8)

Gruß, Alex

Fridolin Walther 6. Okt 2009 10:19

Re: Eigenes Handle finden
 
Zitat:

Zitat von Schwedenbitter
Zitat:

Zitat von Fridolin Walther
Aber wenn Du genau schilderst (am Besten mit exakten Anwendungsnamen) was Du möchtest, wird man Dir sicher nähere Informationen geben können.

Das habe ich schon und niemand hatte bislang eine bessere Idee! Ich gehe jetzt schlafen. Vielleicht hat sich ja bis morgen mein Problem gelöst und jemand eine bessere Idee gepostet.

Wenn Du nicht darauf warten möchtest, das OpenOffice sich beendet, weil Du befürchtest die Synchronisation würde darunter leiden, wäre es evtl. sinnvoll 2 Methoden zu kombinieren:

Mit MSDN-Library durchsuchenFindFirstChangeNotification warten bis sich die Datei ändert und gegebenenfalls synchronisieren und das ganze so lange fortführen bis die Anwendung geschlossen wurde.

Zitat:

Wie gesagt: Ich bin für Tipps immer offen. 8)
Wenn Du von Deiner Fensterlösung nicht weg willst, wäre es eindeutig sinnvoller sich mit EnumDesktopWindows alle Fenster des Desktops zu holen und über die Fenster Klasse die für Dich relevanten Fenster zu identifizieren:
Delphi-Quellcode:
program Project1;
{$APPTYPE CONSOLE}

uses
  Windows;

type
  TOpenOfficeWindow = record
    WindowHandle: THandle;
    WindowTitle: string;
  end;

  TOpenOfficeWindowArray = array of TOpenOfficeWindow;
  POpenOfficeWindowArray = ^TOpenOfficeWindowArray;

function EnumWindowsCallback(hwnd: THandle; WindowArray: POpenOfficeWindowArray)
  : LongBool; stdcall;
const
  WINDOW_TITLE_BUFFER_SIZE = 65 * 1024;
  OPENOFFICE_WINDOW_CLASSNAME = 'SALFRAME';
var
  WindowTitle: array [0 .. WINDOW_TITLE_BUFFER_SIZE] of WideChar;
  WindowClassName: array [0 .. WINDOW_TITLE_BUFFER_SIZE] of WideChar;
begin
  Result := true;
  // Uns interessieren nur sichtbare Fenster
  if IsWindowVisible(hwnd) then
    begin
      // Wir holen uns den ClassName des Fensters
      FillChar(WindowClassName, SizeOf(WindowClassName), 0);
      if (GetClassName(hwnd, @WindowClassName, WINDOW_TITLE_BUFFER_SIZE) > 0)
        and (WindowClassName = OPENOFFICE_WINDOW_CLASSNAME) then
        begin
          // Wir ermitteln den Fenster Titel
          FillChar(WindowTitle, SizeOf(WindowTitle), 0);
          GetWindowText(hwnd, @WindowTitle, WINDOW_TITLE_BUFFER_SIZE);

          // Wir erweitern das übergebene WindowArray um 1 und füllen es mit den ermittelten Informationen
          SetLength(WindowArray^, Length(WindowArray^) + 1);
          WindowArray^[ High(WindowArray^)].WindowHandle := hwnd;
          WindowArray^[ High(WindowArray^)].WindowTitle := WindowTitle;
        end;
    end;
end;

function EraseAndFillWindowArray(var WindowArray: TOpenOfficeWindowArray)
  : Boolean;
begin
  // Array löschen
  SetLength(WindowArray, 0);
  // Wir lassen uns alle Fenster zurückgeben die auf dem Desktop angezeigt werden
  EnumDesktopWindows(0, @EnumWindowsCallback, Cardinal(@WindowArray));
  // Falls Einträge im WindowArray vorhanden sind, geben wir true, ansonsten false zurück
  Result := Length(WindowArray) <> 0;
end;

var
  WindowArray: TOpenOfficeWindowArray;
  i : Integer;

begin
  writeln(EraseAndFillWindowArray(WindowArray));
  writeln;
  for i := 0 to Length(WindowArray) - 1 do
    begin
      writeln('Fenster Handle: ', WindowArray[i].WindowHandle);
      writeln('Fenster Titel: ', WindowArray[i].WindowTitle);
      writeln;
    end;
  readln;
end.
Bei mir ergibt das folgenden Output:
Code:
TRUE

Fenster Handle: 196900
Fenster Titel: On-Access scanner design.docx - OpenOffice.org Writer

Fenster Handle: 527992
Fenster Titel: onaccessscannerdesign.docx - OpenOffice.org Writer
Jetzt könntest Du Dir noch aus dem Fenstertitel den Dateinamen herauspopeln und wüsstest damit sogar welches Fenster zu welcher Datei gehört (vorrausgesetzt die Dateinamen sind unterschiedlich).


Alle Zeitangaben in WEZ +1. Es ist jetzt 20:54 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