Mausklick an Applikation über SendMessage

  • VB.NET
  • .NET 4.5

Es gibt 21 Antworten in diesem Thema. Der letzte Beitrag () ist von f0x.

    Mausklick an Applikation über SendMessage

    Hallo,

    ich möchte in Fensterkoordinaten eines anderen Programms einen Klick absetzen.

    Folgende Deklarationen:

    VB.NET-Quellcode

    1. Option Explicit On
    2. Option Strict On
    3. Public Class Form1
    4. <System.Runtime.InteropServices.DllImport("user32.dll", CharSet:=Runtime.InteropServices.CharSet.Auto)>
    5. Public Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As Integer, ByVal lParam As IntPtr) As IntPtr
    6. End Function
    7. Private Const WM_LBUTTONDOWN As Integer = &H201
    8. Private Const WM_LBUTTONUP As Integer = &H202
    9. <System.Runtime.InteropServices.DllImport("user32.dll", SetLastError:=True, CharSet:=System.Runtime.InteropServices.CharSet.Auto)>
    10. Private Shared Function FindWindow(ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
    11. End Function
    12. Private Declare Function SetForegroundWindow Lib "User32.Dll" (ByVal hWnd As IntPtr) As IntPtr
    13. <System.Runtime.InteropServices.DllImport("user32.dll", SetLastError:=True, CharSet:=System.Runtime.InteropServices.CharSet.Auto)>
    14. Shared Function ClientToScreen(ByVal hwnd As IntPtr, ByRef lpPoint As Point) As Boolean
    15. End Function
    16. Private Declare Function SetCursorPos& Lib "user32" (ByVal p As Point)
    17. Structure PointAPI
    18. Public x As Integer
    19. Public y As Integer
    20. End Structure
    21. Private Declare Function GetCursorPos Lib "user32" (ByRef lpPoint As PointAPI) As Boolean
    22. Private Shared Function MakeLParam(ByVal LoWord As Integer, ByVal HiWord As Integer) As IntPtr
    23. Return New IntPtr((HiWord << 16) Or (LoWord And &HFFFF))
    24. End Function
    25. Dim WindowTitle As String = "BlueStacks"
    26. Dim pStart As New Point(80, 165) 'BlueStacks point to click


    Aufruf:

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. Dim w As IntPtr
    3. w = FindWindow(Nothing, WindowTitle)
    4. Dim pRelative As New Point
    5. pRelative = pStart
    6. Dim c As Boolean = ClientToScreen(w, pRelative)
    7. Dim ClickPos As IntPtr = MakeLParam(pRelative.X, pRelative.Y)
    8. SendMessage(w, WM_LBUTTONDOWN, Keys.LButton, ClickPos)
    9. SendMessage(w, WM_LBUTTONUP, Keys.LButton, ClickPos)
    10. End Sub


    Es funktioniert aber nicht - Kein Klick wahrnehmbar

    Über Call SetCursorPos(pRelative) wird der Cursor relativ zur Fensterposition richtig gesetzt. Daraus schließe ich, daß FindWindow und ClientToScreen erfolgreich sein.

    Ich habe den Code fast komplett aus einem Projekt, was vor 5 Jahren erfolgreich gelaufen ist, deswegen kann ich mir noch weniger erklären wieso es nicht funktioniert. Liegt es am SendMessage ??

    Habt ihr eine Idee?
    Hi, Willkommen im Forum!

    f0xm schrieb:

    Daraus schließe ich, daß FindWindow und ClientToScreen erfolgreich sein.


    Warum nicht testen ob w nach

    VB.NET-Quellcode

    1. w = FindWindow(Nothing, WindowTitle)

    = IntPtr.Zero ist? Wenn != IntPtr.Zero, war es erfolgreich. ClientToScreen gibt einen Boolean zurück, einfach auf erfolg zu testen.

    Mit SendMessage hatte ich auch machmal das Problem das es nicht ging. Kannst es auch mit PostMessage probieren, wie auch mit mouse_event
    pinvoke.net/default.aspx/user32.postmessage
    pinvoke.net/default.aspx/user32.mouse_event

    Um die Position des Cursors zu setzen, braucht keine WinAPI-Funktion nutzen. Das geht auch einfach mit

    VB.NET-Quellcode

    1. Cursor.Position = ...

    docs.microsoft.com/de-de/dotne…ion?view=netframework-4.8
    Cloud Computer? Nein Danke! Das ist nur ein weiterer Schritt zur totalen Überwachung.
    „Wer die Freiheit aufgibt, um Sicherheit zu gewinnen, wird am Ende beides verlieren.“
    Benjamin Franklin
    Willkommen im Forum.

    NoIde schrieb:

    Um die Position des Cursors zu setzen
    dürfte etwas sein, was der TE wohl gar nicht will, sonst würde ich mit mouse_event arbeiten.
    Du willst also in bluestacks was anklicken. Schau mal hier und hier zum Thema »andere Programme auslesen und fernsteuern« rein. Vielleicht lässt sich so das bisher leider nicht näher beschriebene Problem lösen. Was zur Frage führt: Was willst Du erreichen? Einen Mausklick irgendwo abzusetzen ist ja nur Mittel zum Zweck. Und ist da vielleicht nicht sowas wie ComboKey besser geeignet?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „VaporiZed“ ()

    Jou, jetzt wo du es sagts wird mir das gerade auch klar. Hatte mich von SetCursorPos irritieren lassen. Ich glaub ich mach Pause, scheint zu viel Input gewesen zu sein. HLSL macht mich bekloppt.
    Cloud Computer? Nein Danke! Das ist nur ein weiterer Schritt zur totalen Überwachung.
    „Wer die Freiheit aufgibt, um Sicherheit zu gewinnen, wird am Ende beides verlieren.“
    Benjamin Franklin
    Danke für eure Antworten.

    Die Rückgabewerte von FindWindow und ClientToScreen hatte ich ja überprüft. War angedeutet mit der Information, daß beim testweisen setzen des Cursor er korrekt positioniert wird... geht ja nur dann wenn beides geklappt hat.

    VaporiZed hat recht, ich will das ohne setzen des Cursor lösen, darum SendMessage.

    Ich hab es auch in Chrome probiert, selbiges. Es wird nicht geklickt. Ich verstehe halt nicht wieso das jetzt nicht mehr klappen will.

    PostMessage hatte ich bisher vermieden, schaue ich mir aber an. Auch eure Links führ ich mir jetzt mal zu Gemüte.

    Wenn jemandem noch was einfällt gerne schreiben.

    Danke!
    Ich hab mir das nun doch noch mal angeschaut. Dabei stellte ich fest, das du auf dem richtigen Weg warst. Eine kleinigkeit, welche mir nicht sofort aufviel ist, es reicht wenn du einfach die Coordinate angibst, ohne den "Punkt" mit ClientToScreen zu bearbeiten. Bin gerade nicht ganz sicher, kann sogar sein das du das Handle des Buttons ermitteln musst und dieses für SendMessage nutzen, beim BlueStacks-Android-Emulator, kann ich mir jedenfalls vorstellen, das es so geht. Glaube jedenfalls weniger, das für jedes Android-Steuerelement ein Windows-SteuerElement erzeugt wird.

    Hab das Testergebnis mal festgehalten. Gut in der Direktfenster-Ausgabe zu sehen.


    Spoiler anzeigen

    VB.NET-Quellcode

    1. Option Strict On
    2. Imports System.Runtime.InteropServices
    3. Public Class FrmMain
    4. <DllImport("user32.dll", CharSet:=Runtime.InteropServices.CharSet.Auto)>
    5. Public Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As Integer, ByVal lParam As IntPtr) As IntPtr
    6. End Function
    7. <System.Runtime.InteropServices.DllImport("user32.dll", SetLastError:=True, CharSet:=System.Runtime.InteropServices.CharSet.Auto)>
    8. Private Shared Function FindWindow(ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
    9. End Function
    10. Private Function MakeLParam(ByVal LoWord As Integer, ByVal HiWord As Integer) As IntPtr
    11. Return New IntPtr((HiWord << 16) Or (LoWord And &HFFFF))
    12. End Function
    13. Dim WindowTitle As String = "Title"
    14. Enum WM_CONST
    15. WM_LBUTTONDOWN = &H201
    16. WM_LBUTTONUP = &H202
    17. End Enum
    18. Private Sub BtnMakeIt_Click(sender As Object, e As EventArgs) Handles BtnMakeIt.Click
    19. Dim hwnd As IntPtr = FindWindow(Nothing, WindowTitle)
    20. If hwnd <> IntPtr.Zero Then
    21. Dim ClickPos As IntPtr = MakeLParam(100, 400)
    22. SendMessage(hwnd, WM_CONST.WM_LBUTTONDOWN, Keys.LButton, ClickPos)
    23. SendMessage(hwnd, WM_CONST.WM_LBUTTONUP, Keys.LButton, ClickPos)
    24. Else
    25. MessageBox.Show("Window not found!")
    26. End If
    27. End Sub
    28. End Class



    Cloud Computer? Nein Danke! Das ist nur ein weiterer Schritt zur totalen Überwachung.
    „Wer die Freiheit aufgibt, um Sicherheit zu gewinnen, wird am Ende beides verlieren.“
    Benjamin Franklin

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „NoIde“ ()

    @f0xm Ebenfalls Willkommen im Forum. :thumbup:
    Wenn Du mit "fremden" Fenstern reden willst, schau auch mal hier rein:
    Andere Programme fernsteuern
    externe .Net-Programme auslesen und manipulieren
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    VB-Fragen über PN / Konversation werden ignoriert!
    Hallo Nolde,

    danke dir für deinen Test, das hat mich auf neue Ideen gebracht. Und ja, ich kann für die Elemente im Emulator keine Handles ermitteln, deswegen einfach Klick auf die Koordinaten des Fensters.

    Ich hab das nun selbst mal mit einem zweiten .NET Programm probiert die Clicks zu registrieren. Es ist wirklich merkwürdig. Klicks auf die Form des zweiten Programms werden ausgeführt. Klicks in eine Picturebox feuern aber weder das _Click noch das _MouseClick Event.



    Ich überlege ernsthaft nochmal ein Windows 7 zu installieren und zu schauen wie es sich da verhält.

    Ich hab es jetzt mit SendMessage und PostMessage probiert, Ergebnisse identisch.

    @RodFromGermany Dankeschön!
    Ich hab das auch probiert, einmal mit der ausführenden Form selbst und dann noch mit Paint und notepad. Das Form registriert den simulierten Mausklick, Paint und notepad nicht. Win10 64Bit mit Adminrechten.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.
    Also in diesem Fall, brauchst du das Handle der PictureBox. Eine PictureBox ist js streng genommen auch ein Window, wie auch Buttons etc..... Schau dir mal die Function EnumChildWindows an:

    pinvoke.net/default.aspx/user32.enumchildwindows

    Also wie bisher das Hauptfenster ermitteln, dann mit EnumChildWindow das Handle des Controls das anzusprechen ist finden. Dann sollte das auch bei der PictureBox funktionieren. Kleiner Tipp, nutze das Tool spy++ welches mit VS mitgeliefert wird. Such mal im Installationsordner von VS nach der Anwendung spyxx.exe und führe sie aus.

    VaporiZed schrieb:

    notepad


    Bei Notepad erinnere ich mich grad an was. Da muss man ein Child-Window finden/nutzen, dann geht es dort auch. Das Hauptfenster ist da nicht der Bereich wo man den Text bearbeiten kann, auch wenn's so ausschaut.
    Cloud Computer? Nein Danke! Das ist nur ein weiterer Schritt zur totalen Überwachung.
    „Wer die Freiheit aufgibt, um Sicherheit zu gewinnen, wird am Ende beides verlieren.“
    Benjamin Franklin
    Argh. Hast recht. Notepad hat ja n "Edit"-ChildWindow. Dessen Handle hergenommen und der Mausklick kommt auch an.
    Und bei MSPaint nennt sich das Teil "Afx:00007FF66BA90000:8". Dank meiner SpyApp krieg ich zumindest Name und Handle der anzuvisierenden Komponenten her.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.
    Hallo,


    @VaporiZed Hm.. also kannst du das Problem nachvollziehen. Und aus dem gleichen Grund spricht der Klick wohl auch auf BlueStacks nicht an, auch Klicks in den Chrome-Browser werden ignoriert. Auch ich hab das Programm testweise schon ein paar mal als Admin ausgeführt gehabt. Trotzdem muß es ja fast eine Art Sicherheitsmechanismus, was anderes kann ich mir mittlerweile nicht mehr vorstellen.

    @'Nolde' Ich habs mit dem Handle der PictureBox nicht probiert weil es mir für BlueStacks nichts helfen würde, da hab ich kein Handle für die zu klickenden Elemente zur Verfügung.
    Wenn ich später ein wenig Zeit finde, teste ich das mal mit BlueStacks inner VM aus. Geht ja um den Emulator nicht?

    @f0xm

    Wie den grössten Teil der User hier, passiert es dir auch. In meinem Usernamen ist kein L drin. Was aussieht wie ein L ist ein grosses i.
    Cloud Computer? Nein Danke! Das ist nur ein weiterer Schritt zur totalen Überwachung.
    „Wer die Freiheit aufgibt, um Sicherheit zu gewinnen, wird am Ende beides verlieren.“
    Benjamin Franklin
    So hab jetzt Zeit gefunden. Also dein Fenster kann so wie du es hattest nicht gefunden werden. Ich habe jetzt BlueStacks am laufen und habe mit spy++ geschaut. Der WindowTitle stimmt nicht überein. Ich schau mal was sich machen lässt.



    Edit stimmt scheinbar doch, hab title und classname verdreht. Sorry.
    Cloud Computer? Nein Danke! Das ist nur ein weiterer Schritt zur totalen Überwachung.
    „Wer die Freiheit aufgibt, um Sicherheit zu gewinnen, wird am Ende beides verlieren.“
    Benjamin Franklin

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „NoIde“ ()

    Also so das der Cursor dabei nicht bewegt wird, habe ich es bisher nicht geschafft. Nur das er versetzt wird, es wird geklickst und der Cursor wieder auf die alte Position zurück gesetzt. Ich probiere später noch mal weiter.
    Cloud Computer? Nein Danke! Das ist nur ein weiterer Schritt zur totalen Überwachung.
    „Wer die Freiheit aufgibt, um Sicherheit zu gewinnen, wird am Ende beides verlieren.“
    Benjamin Franklin
    Also ich hab jetzt nochmal probiert, es will nicht ohne den Cursor zu versetzen. Ankommen tun die Messages, hab mal ein paar absichtlich Schwachsinns-Messages unter anderem WM_CLOSE reingeschickt. Hauptfenster schliessen oder Programmteile zum Absturz bringen kein Thema, aber klicksen will nicht.



    Ich lass es jetzt sein. Du kannst selbst noch weiter probieren oder einfach diesen Code erweitern. Mit dem Code kannst du egal wo auf dem Bildschirm klicksen.

    VB.NET-Quellcode

    1. Imports System.Runtime.InteropServices
    2. Public Class Form1
    3. <DllImport("user32.dll")>
    4. Private Shared Sub mouse_event(dwFlags As UInteger, dx As UInteger, dy As UInteger, dwData As UInteger, dwExtraInfo As Integer)
    5. End Sub
    6. Private Function NormalizeX(ByVal x As Integer) As Integer
    7. Return CInt(x * 65535 / Screen.PrimaryScreen.Bounds.Width)
    8. End Function
    9. Private Function NormalizeY(ByVal y As Integer) As Integer
    10. Return CInt(y * 65535 / Screen.PrimaryScreen.Bounds.Height)
    11. End Function
    12. <Flags()>
    13. Public Enum MouseEventFlags As UInteger
    14. MOUSEEVENTF_ABSOLUTE = &H8000
    15. MOUSEEVENTF_MOVE = &H1
    16. MOUSEEVENTF_LEFTDOWN = &H2
    17. MOUSEEVENTF_LEFTUP = &H4
    18. MOUSEEVENTF_RIGHTDOWN = &H8
    19. MOUSEEVENTF_RIGHTUP = &H10
    20. MOUSEEVENTF_MIDDLEDOWN = &H20
    21. MOUSEEVENTF_MIDDLEUP = &H40
    22. MOUSEEVENTF_XDOWN = &H80
    23. MOUSEEVENTF_XUP = &H100
    24. MOUSEEVENTF_WHEEL = &H800
    25. MOUSEEVENTF_HWHEEL = &H1000
    26. End Enum
    27. Private Sub ClickIt()
    28. Dim pos As Point = Cursor.Position
    29. mouse_event(MouseEventFlags.MOUSEEVENTF_LEFTDOWN Or MouseEventFlags.MOUSEEVENTF_ABSOLUTE Or MouseEventFlags.MOUSEEVENTF_MOVE, NormalizeX(80), NormalizeY(170), 0, 0)
    30. mouse_event(MouseEventFlags.MOUSEEVENTF_LEFTUP, 0, 0, 0, 0)
    31. mouse_event(MouseEventFlags.MOUSEEVENTF_ABSOLUTE Or MouseEventFlags.MOUSEEVENTF_MOVE, NormalizeX(pos.X), NormalizeY(pos.Y), 0, 0)
    32. End Sub
    33. End Class
    Cloud Computer? Nein Danke! Das ist nur ein weiterer Schritt zur totalen Überwachung.
    „Wer die Freiheit aufgibt, um Sicherheit zu gewinnen, wird am Ende beides verlieren.“
    Benjamin Franklin
    Hi Noide,

    danke für deine Tests. WM_CLOSE hatte ich auch schon probiert und weil praktisch alles andere geht bin ich auf evtl. Sicherheitsthema gekommen. Cursor setzen war halt genau das was ich nicht wollte, darum probier ich jetzt schon so lang rum. Ich hatte es auf Win7 laufen, da sind die Klicks sogar angekommen wenn das Fenster verdeckt war... minimiert ist ein Sonderfall, das hatte damals schon nicht geklappt aber hinter mehreren anderen Fenstern war kein Problem.

    Lieben Dank für deine Bemühungen, ich werd mal gucken was ich noch so rausfinde. Würde es echt gern nochmal unter Windows7 nachstellen.

    Liebe Grüße.