![]() |
Handle von Sub-Fenster anderer Applikation implementieren
Hallo Wissende,
ich möchte eine andere Application starten und mir das Handle eines der Unter-Forms in den Canvas eines TIMage oder eine TPaintbox zeichnen lassen. Ich weiss, dass das Kollegen mit C# schon gemacht haben. Wie ich die andere Applikation starte und das Handle des Fenster bekomme, habe ich mir hier im Forum schon zusammen gesucht. Aber wenn ich dann das erhaltene Handle zuweise bleibt das Image oder die Paintbox leer. Was mache ich da falsch? Hier mal mein Code:
Delphi-Quellcode:
Es ist so, dass ich keine Fehlermeldung erhalte, das Handle wird also korrekt ermittelt.
unit Unit1;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; type PFindWindowStruct = ^TFindWindowStruct; TFindWindowStruct = record Caption: string; ClassName: String; WindowHandle: THandle; end; type TForm1 = class(TForm) ListBox1: TListBox; Image1: TImage; Button1: TButton; PaintBox1: TPaintBox; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; var Form1: TForm1; implementation {$R *.dfm} //sammeln aller infos und schreiben dieser in eine listbox - nur so, zum testen function EnumWinProc(Wnd: THandle; LParam: LongInt): Boolean; stdcall; var WinCaption : string; Len: integer; begin Result := True; Len := GetWindowTextLength(Wnd); SetLength(WinCaption, Len); GetWindowText(Wnd, PChar(WinCaption), Len+1); if Trim(WinCaption) <> '' then Form1.Listbox1.Items.Add(Format('%.6x : %s', [Wnd, WinCaption])); end; procedure TForm1.FormCreate(Sender: TObject); begin EnumWindows(@EnumWinProc, 0); end; function EnumWindowsProc(hWindow: hWnd; lParam: LongInt): boolean; stdcall; var lpBuffer: PChar; WindowCaptionFound: boolean; ClassNameFound: boolean; begin GetMem(lpBuffer, 255); result:=true; WindowCaptionFound:=false; ClassNameFound:=false; try if GetWindowText(hWindow, lpBuffer,255)>0 then if Pos(PFindWindowStruct(lParam).Caption, StrPas(lpBuffer))>0 then WindowCaptionFound:=true; if PFindWindowStruct(lParam).ClassName='' then ClassNameFound:=true else if GetClassName(hWindow, lpBuffer, 255)>0 then if Pos(PFindWindowStruct(lParam).ClassName, StrPas(lpBuffer))>0 then ClassNameFound:=true; if (WindowCaptionFound and ClassNameFound) then begin PFindWindowStruct(lParam).WindowHandle:=hWindow; result:=false; end; finally FreeMem(lpBuffer, sizeof(lpBuffer^)); end; end; function FindAWindow(WinCaption: string; WinClassName: string): THandle; var WindowInfo: TFindWindowStruct; begin with WindowInfo do begin caption := WinCaption; className := WinClassName; WindowHandle := 0; EnumWindows(@EnumWindowsProc, LongInt(@WindowInfo)); result := WindowHandle; end; end; //hier wird das fenster gesucht und das handle zugewiesen procedure TForm1.Button1Click(Sender: TObject); var TheWindowHandle: THandle; begin TheWindowHandle:=FindAWindow('Renderer', ''); if TheWindowHandle=0 then ShowMessage('Window not found!') else PaintBox1.Canvas.Handle := (TheWindowHandle); PaintBox1.Repaint; //ShowWindow(TheWindowHandle, SW_SHOWMINNOACTIVE); //hier wird das fenster in den vordergrund geholt //allerdings samt des hauptfenstrers der anderen applikation //BringWindowToTop(TheWindowHandle); end; end. Ich mache Scheinbar nur noch einen Fehler bei der Übergabe des Handles an die Paintbox, respektive das Image. Wäre das überhaupt der richtige Weg, oder sollte ich es besser anders machen? |
Re: Handle von Sub-Fenster anderer Applikation implementiere
Zitat:
Ich vermute mal, du willst, die Oberfläche eines Fenster einer anderen Anwendung in eine Paintbox zeichnen.
Delphi-Quellcode:
Hier weißt du nur dem Canvas der Paintbox ein Handle zu. So geht das nicht. Du musst dir mit
PaintBox1.Canvas.Handle := (TheWindowHandle);
PaintBox1.Repaint; ![]() |
Re: Handle von Sub-Fenster anderer Applikation implementiere
Zitat:
Absolut richtig vermutet. :-) Da ich so was noch nie gemacht habe, kann es schon mal passieren, dass sich falsch ausdrückt und so Mißverständnisse aufkommen. Ich schaue mal ob ich hier im Forum was zu Deinem Hinweis finde, da mein Englisch leider nicht so doll ist, als dass ich was mit Deinem Link anfangen könnte. Was ich nicht ganz verstehe ist, dass Du einmal schreibst, dass das mit einem Handle so nicht geht und später schreibst Du dann, dass ich mir mit GetDC ein Handle auf das Fenster holen soll. Ist also das Ergebis über GetDC ein anderes, als das über die FindAWindow-Methode? |
Re: Handle von Sub-Fenster anderer Applikation implementiere
GetDC holt Dir einen DeviceContext auf die Zeichenfläche des Fensters (also quasi dessen Canvas.Handle).
|
Re: Handle von Sub-Fenster anderer Applikation implementiere
Ja. Zum einem meinte ich, dass mit dem einfachen zu weisen eines Fensterhandles nicht geht und zum anderem brauchst du ein Handle auf den zugehörigen Gerätekontext (Devicecontext), also ein Handle auf die Zeichenfläche des Fensters. Die Eigenschaft Canvas entspricht übrigens dem, was Windows unter einem Gerätekontext versteht.
|
Re: Handle von Sub-Fenster anderer Applikation implementiere
Hier ein schnell dahingeschludertes Beispiel:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var DC: hDC; Wnd: HWnd; begin if ShellExecute(0,'open','calc.exe',nil,nil,SW_SHOW) > 32 then begin Sleep(500); Wnd := FindWindow(nil,'Rechner'); if Wnd <> 0 then begin DC := GetDC(Wnd); if DC <> 0 then begin BitBlt(Canvas.Handle,0,0,ClientWidth,ClientHeight,DC,0,0,SRCCOPY); ReleaseDC(DC,Wnd); end; end; end; end; |
Re: Handle von Sub-Fenster anderer Applikation implementiere
Erstmal vielen Dank für Euren Support und die aufgebrachte Geduld.
Das Beispiel sollte mir sicher helfen den Vorgang zu realisieren und zu verstehen. Feedback versprochen! |
Re: Handle von Sub-Fenster anderer Applikation implementiere
Also,
grundsätzlich funktioniert der Code schon ganz gut. Es wird zwar zu viel gezeichnet, aber das liegt sicher an den gemachten Angaben im BitBlt. Ausserdem frage ich mich, wie ich es anstellen soll, dass das zeichnen nicht nur beim Betätigen des Buttons einmalig erfolgt, sondern permanent. Das Beispiel mit dem Rechner finde ich schon ganz gut. Wenn ich also im Rechner eine Rechenopertaion durchführen würde, wäre es klasse, wenn die Aktionen immer alle gezeichnet werden würden. Ich habe hierzu mal das ReleaseDC(DC,Wnd); aus dem Code entfernt, aber ich bin mir sicher, dass das noch nicht reichen wird. Ich Sollte ich einfach über einen Timer das BitBlt immer wieder aufrufen, oder geht es auch eleganter? |
Re: Handle von Sub-Fenster anderer Applikation implementiere
Nun, wenn etwas in regelmäßigen Intervallen ausgeführt werden soll, dann nimmt man einen Timer.
|
Re: Handle von Sub-Fenster anderer Applikation implementiere
Gibt es denn auch die Möglichkeit die Grösse des externen Fensters abzufragen, damit man beim BitBlt auch nur die Grösse zeichnet, die das Fenster hat..?
|
Re: Handle von Sub-Fenster anderer Applikation implementiere
Du könntest mit
![]() |
Re: Handle von Sub-Fenster anderer Applikation implementiere
Danke, das funktioniert perfekt, wenn man sich noch einen Offset für den Fenstertitel und die Rahmenbreite deklariert.
Nun stellt sich mir nur noch die Frage, warum dass mit der Calc.exe so gut funktioniert, aber eben mit dem SubForm der betreffenden Exe nicht. Das SubForm wird, wenn es auf dem MainForm eingebettet ist, NICHT gefunden. Wenn man händisch aus dem MainForm herauszieht, was man gottseidank speichern kann, wird es gefunden, aber leider erhalte ich keinen Screenshot von dem Fenster mit der Funktion FindWindow oder FindAWindow (siehe weiter oben). Gibt es zu dieser Problemtik noch Vorschläge oder Ideen? |
Re: Handle von Sub-Fenster anderer Applikation implementiere
![]() Zitat:
![]() [edit] Nachtrag: den Clientbereich eines Fensters bekommst Du mit ![]() |
Re: Handle von Sub-Fenster anderer Applikation implementiere
Danke für die beiden weiteren Hinweise.
Ich schaus mir an. |
Re: Handle von Sub-Fenster anderer Applikation implementiere
Hallo,
ich habe, da ich mit den Pointern und den gesamten Zusammenhängen noch nicht ganz durchsehe mal etwas gegoogelt und folgendes gefunden.
Delphi-Quellcode:
In dem Memo wird das SubForm, welches ich suche, definitiv gelistet. Da ich aber die SubForms nicht listen will, sondern nur auf das eine zugreifen will, frage ich mich nun, wie ich das so umschreiben kann, dass ich das Handle des SubForms erhalte und es dann über die GetDC() schicken kann.
function EnumProc(wnd: HWND; Lines: TStrings): BOOL; stdcall;
var buf, Caption: array[0..255] of char; begin Result := True; GetClassName(wnd, buf, SizeOf(buf) - 1); SendMessage(wnd, WM_GETTEXT, 256, Integer(@Caption)); Lines.Add(Format('ID: %d, ClassName: %s, Caption: %s', [GetDlgCtrlID(wnd), buf, Caption])); end; procedure TForm1.PrintDialog1Show(Sender: TObject); begin Memo1.Clear; EnumChildWindows(printdialog1.Handle, @EnumProc, Integer(memo1.Lines)); end; Ich habe versucht die EnumProc umzuschreiben, aber leider verlief das ohne Erfolg, da ich die Caption wohl nicht in der EnumProc direkt erfragen kann...Was mach ich da nur falsch? |
Re: Handle von Sub-Fenster anderer Applikation implementiere
Also ich habe es nun doch scheinbar geschafft das Handle des SubForms zu erhalten. Leider ist es aber so, dass es wohl nicht möglich scheint den "Screenshot" von einem verdeckten Fenster zu machen. Es wird gezeichnet, aber eben nur das, was auf dem Screen zu sehen ist.
Warum nur? |
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:21 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz