2013-03-20 8 views
13

Ich habe das Hwnd eines VCL-Steuerelements, das sich in einem anderen Prozessfenster befindet. Gibt es eine Möglichkeit, den VCL-Namen (TControl.Name -Eigenschaft) dieses Steuerelements über die Windows-API abzurufen? Ich brauche den Namen, weil es mehrere TEdits in diesem Fenster gibt, und ich muss die eine identifizieren, die ich möchte, um eine WM_SETTEXT Nachricht an es zu senden.Gibt es eine Möglichkeit, den Namen eines VCL-Steuerelements über die Windows-API abzurufen?

Beide Anwendungen mit Delphi 2010 gebaut wurden

+0

Wenn Sie den Code steuern Sie auf einen benutzerdefinierten Fenster Nachricht – Remko

+1

Oder einfach definieren Sie Ihren eigenen Satz von WM_USER Nachrichten durch Rücksendung der Name reagieren kann –

+0

Haben Sie die Kontrolle über die beiden Anwendungen? Kannst du beides neu bauen? – kobik

Antwort

14

Delphi hat eingebaute Funktion FindControl(), die TWinControl der angegebenen hWnd zurückgibt. Aber es funktioniert für die gleiche Instanz von VCL. Ich denke, du solltest es untersuchen. Nachdem Sie den Zeiger auf das TWinControl-Objekt gesetzt haben, befindet sich sein Name (String) unter +8 offset. Sie können ReadProcessMemory versuchen, es zu lesen. Das Hauptproblem besteht darin, eine Version von FindControl() zu erstellen, die Ihren Anforderungen entspricht.

Edit: (habe es endlich: D) Aufruf GetWinControlName Funktion

// Get Pointer to TWinControl in another process 
function GetWinControl(Wnd: HWND; out ProcessId: THandle): Pointer; 
var 
    WindowAtomString: String; 
    WindowAtom: ATOM; 
begin 
    if GetWindowThreadProcessId(Wnd, ProcessId) = 0 then RaiseLastOSError; 

    // This is atom for remote process (See controls.pas for details on this) 
    WindowAtomString := Format('Delphi%.8X',[ProcessID]); 
    WindowAtom := GlobalFindAtom(PChar(WindowAtomString)); 
    if WindowAtom = 0 then RaiseLastOSError; 

    Result := Pointer(GetProp(Wnd, MakeIntAtom(WindowAtom))); 
end; 

function GetWinControlName(Wnd: HWND): string; 
var 
    ProcessId: THandle; 
    ObjSelf: Pointer; 
    Buf: Pointer; 
    bytes: Cardinal; 
    destProcess: THandle; 
begin 
    ObjSelf := GetWinControl(Wnd, ProcessId); 

    destProcess := OpenProcess(PROCESS_VM_READ, TRUE, ProcessId); 
    if destProcess = 0 then RaiseLastOSError; 

    try 
    GetMem(Buf, 256); 
    try 
     if not ReadProcessMemory(destProcess, Pointer(Cardinal(ObjSelf) + 8), Buf, 4, bytes) then RaiseLastOSError; 
     if not ReadProcessMemory(destProcess, Pointer(Cardinal(Buf^)), Buf, 256, bytes) then RaiseLastOSError; 
     Result := PChar(Buf); 
    finally 
     FreeMem(Buf); 
    end; 
    finally 
    CloseHandle(destProcess); 
    end; 
end; 
+0

Jetzt muss ich nur eine 'FindControl'-Funktion finden, die in einem anderen Prozess funktioniert:/ –

+0

Versuchen Sie, diesen Teil der inneren 'ObjectFromHWnd'-Funktion' Result: = Pointer (SendMessage (Handle, RM_GetObjectInstance, 0, 0)) 'zu verwenden. Ich denke, Sie sollten alle diese ProcessId-Prüfungen entfernen. – Samaliani

+0

Der Offset hängt von der Delphi-Version ab, die zum Erstellen des anderen Steuerelements verwendet wurde. TObject.InstanceSize wurde geändert, als sie System.TMonitor einführten. –

6

Nein, es gibt keine Funktion Windows-API, die der Kontrolle des Namens wird ergeben. Das ist ein privates Delphi-Implementierungsdetail.

Wenn Sie den Code des Zielprozesses kontrollieren, können Sie klar eine Form von IPC implementieren, um das Problem zu lösen. Sonst wird jede Lösung, die den Kontrollnamen hervorbringt, ziemlich abscheuliches Hacking beinhalten. Ein Ansatz wäre, eine DLL in den Prozess zu integrieren, die mit der gleichen Laufzeitversion erstellt wurde. Holen Sie diese DLL, um die VCL-Kontrollreferenz von der HWND zu finden und den Namen auszulesen. Es gibt viele Varianten dazu und die schön gemachten ReadProcessMemory Tricks von @ Samaliani's Antwort ist typisch für die Reifen, durch die man springen muss.

Allerdings kann ich mir eine viel einfachere Lösung für Ihr Problem vorstellen. Suchen Sie nach den Handles für alle Bearbeitungssteuerelemente, und verwenden Sie diese Handles, um die Koordinaten der Steuerelemente zu erhalten. Die relativen Positionen der Bearbeitungssteuerelemente reichen aus, um zu ermitteln, welches das gewünschte Ziel ist. Und lies bitte unten die @ dthorpe Kommentare für weitere nützliche Gedanken.

+2

Der gemeine Hack eines Mannes ist das patentierte Testautomatisierungsrahmenwerk eines anderen Mannes. – dthorpe

+0

@dthorpe In der Tat so. Magst du meine alternative Lösung? –

+2

Vergleichen von Fensterrects ist ausreichend für manuelle Bestätigung ("ist das das?"), Aber nicht langfristig zuverlässig. Fenstergrößen und -positionen können sich mit der Lokalisierung ändern. Sobald das Ziel identifiziert ist, ist die Erinnerung an den untergeordneten Fensterindex oder den Tab-Reihenfolge-Index im Laufe der Zeit möglicherweise ein zuverlässigeres Tag. Die Reihenfolge der Tabs ändert sich normalerweise nicht in der Lokalisierung. – dthorpe

Verwandte Themen