Ungültiger threadübergreifender Vorgang

  • VB.NET

Es gibt 24 Antworten in diesem Thema. Der letzte Beitrag () ist von Radinator.

    Ungültiger threadübergreifender Vorgang

    Hallo leute ich schon wider.. :D

    Ich hab mein Timer.tick nun von ein neuen Thread gestartet, und es kommt die fehler meldung.


    Ein Ausnahmefehler des Typs "System.InvalidOperationException" ist in System.Windows.Forms.dll aufgetreten.

    Zusätzliche Informationen: Ungültiger threadübergreifender Vorgang: Der Zugriff auf das Steuerelement Form1 erfolgte von einem anderen Thread als dem Thread, für den es erstellt wurde.


    auf diesem abschnitt:

    VB.NET-Quellcode

    1. Dim webLoc As Point = PointToScreen(WebBrowser1.Location)



    Wen ich CheckForIllegalCrossThreadCalls = False hinzufüge läuft alles um einiges schneller und saubere, wie im haupt Thread. Allerding hört der Teimer zwischen dursch auf zu arbeiten.


    liegt es daran wei der webbrowser auf dem form1 liegt bevor ich den zweiten Thread starte, was mache ich den da.

    Lg :)
    In Threads nicht auf die GUI zugreifen, dann knallt es auch nicht. Oder aber mit Invok/BeginInvoke arbeiten, dass kostet aber wieder Zeit...

    Gerne kannst du ach etwas mehr Code zeigen, dann kann man einfacher helfen.
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen
    Also ich habe das so versucht was zwahr leuft aber ich nicht so sicher bin ob das so ok ist oder es was besere gibt.

    VB.NET-Quellcode

    1. Delegate Sub webbrowser2callback([WebBrowser2] As WebBrowser)
    2. Private Sub timer1start()
    3. Dim reload As Thread = New Thread(AddressOf timer12)
    4. reload.Start()
    5. End Sub
    6. Private Sub timer12()
    7. Dim d As New webbrowser2callback(AddressOf timer13)
    8. Me.Invoke(d, New Object() {[WebBrowser2]})
    9. End Sub
    10. Private Sub timer13()
    11. Timer1.Start()
    12. Timer1.Interval = 50
    13. Application.DoEvents()
    14. End Sub


    WEIL..

    Jetzt ruckelt alles wider und wen ich mit der maus über der browser fahre oder label,button etc kann ich richtig sehen wie die pixel such funktion schneller arbeitet als wen ich die maus da drüber nicht bewege.

    Edit:

    CheckForIllegalCrossThreadCalls = False hier mit lief alles sauber und super schnell, jetzt findet er mir die pixeln nur schnell wen ich mit der maus schnnel über button etc fahre, sonst ruckelt und dauert evig...

    mrMo schrieb:

    In Threads nicht auf die GUI zugreifen, dann knallt es auch nicht.


    ErfinderDesRades schrieb:

    Lass den Timer seinen Job ganz normal im MainThread machen, dann tritt auch kein ungültiger threadübergreifender Vorgang auf.


    Ist das iwie schwer zu verstehen, oder warum präsentierst du jetzt dennoch Code, der genau das versucht, was nicht geht?

    Und was wir dir ja auch gesagt haben, dasses nicht geht, und das sagt ja auch die Fehlermeldung - ist das iwie schwer zu kapieren, oder meinst du, du könntest durch Hartnäckigkeit die Realität iwie umstimmen? ;)
    Nein aber ich hab auch erklärt was passiert, warum das so nicht laufen kann, dann kannst du mir erklären wie ich es richtig mache.
    Ddamit das nicht so ruckelt und die maus kein einfluss auf meine such funktion hatt wenn über die sachen gehe?


    VB.NET-Quellcode

    1. Declare Auto Sub mouse_event Lib "user32" (ByVal dwFlags As Integer, ByVal dx As Integer, ByVal dy As Integer, ByVal cButtons As Integer, ByVal dwExtraInfo As IntPtr)
    2. Const MOUSEEVENTF_LEFTDOWN As Integer = &H2
    3. Const MOUSEEVENTF_LEFTUP As Integer = &H4
    4. ' capture area as BMP
    5. Private Function CaptureToBitmap(ByVal X As Integer, ByVal Y As Integer, ByVal W As Integer, ByVal H As Integer) As Bitmap
    6. Dim img As New Bitmap(W, H)
    7. Using g = Graphics.FromImage(img)
    8. g.CopyFromScreen(New Point(X, Y), Point.Empty, New Size(W, H))
    9. End Using
    10. Return img
    11. End Function
    12. Private Sub Timer1_Tick(ByVal Sender As Object, ByVal e As EventArgs) Handles Timer1.Tick
    13. Dim X, Y As Integer
    14. ' get browser control location on screen
    15. Dim webLoc As Point = PointToScreen(WebBrowser2.Location)
    16. ' get browser size
    17. Dim webSiz As Size = WebBrowser2.Size
    18. ' take snap shot of browser
    19. Dim WebBmp As Bitmap = CaptureToBitmap(webLoc.X, webLoc.Y, webSiz.Width, webSiz.Height)
    20. ' copy image to integer array
    21. Dim b(WebBmp.Width * WebBmp.Height - 1) As Integer
    22. Dim bd As BitmapData = WebBmp.LockBits(New Rectangle(Point.Empty, WebBmp.Size), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb)
    23. Marshal.Copy(bd.Scan0, b, 0, b.Length)
    24. WebBmp.UnlockBits(bd)
    25. Dim movColor As Integer = ColorTranslator.FromHtml("#575C5F").ToArgb()
    26. For iMov As Integer = 0 To b.Length - 1
    27. If b(iMov) = movColorx Then
    28. X = iMov Mod WebBmp.Width
    29. Y = iMov \ WebBmp.Width
    30. movementfound = True
    31. End If
    32. Next
    33. if movementfound = True Then
    34. Cursor.Position = PointToScreen(New Point(X , Y ))
    35. mouse_event(MOUSEEVENTF_LEFTDOWN + MOUSEEVENTF_LEFTUP, 0, 0, 0, IntPtr.Zero)
    36. Else
    37. Labe1.Text = "Not Found"
    38. End If


    Viel mehr ist nicht im teimer trozdem Dürfte es nicht schneler suchen und so laufen.
    jo, das ist eine ziemlich zeitfressende Methode, hat auch kaum was mit Controls zu tun, und sollte man in einen NebenThread auslagern.
    Also schreib mal erstmal die Methode so um, dass sie vom TimerTick aus aufgerufen wird, und dabei das zu fotografierende Rechteck übergeben wird.

    Und die Timer.Interval sollte erstmal nicht kleiner als 500 sein - sonst ist das womöglich einfach nicht zu schaffen.
    Ja danke Das könnte mir echt helfen :D

    Ja mit dem teimer ist mir bewust ich hab nur rum probiert da man da es am meisten gesehen hat, beim kollegen am laptop A4000 cpu z.b ist das so das der überhapt nix gesucht hat bis man mit der mauszeiger über die browser etc gefahren ist, noch schlimmer wie oben erklärt.


    Ich werd jetzt erstmal rum probieren, jedenfals ist das ein guter einsatz thx :thumbsup:
    Also schreib mal erstmal die Methode so um, dass sie vom TimerTick aus aufgerufen wird, und dabei das zu fotografierende Rechteck übergeben wird.


    Gennau das ist grade mein problem.
    Ich hab das jetzt so gemacht

    Neues thead da ist meine such funktion.

    VB.NET-Quellcode

    1. Private Sub timer1starttr()
    2. Dim reload As Thread = New Thread(AddressOf Threadtimer1)
    3. reload.Start()
    4. End Sub
    5. Dim webLocThread1 As Point
    6. Dim webSizThread1 As Size
    7. Private Sub Threadtimer1()
    8. Dim webLoc As Point
    9. Dim webSiz As Size
    10. webLoc = webLocThread1
    11. webSiz = webSizThread1
    12. Dim WebBmp As Bitmap = CaptureToBitmap(webLoc.X, webLoc.Y, webSiz.Width, webSiz.Height)
    13. Dim b(WebBmp.Width * WebBmp.Height - 1) As Integer
    14. Dim bd As BitmapData = WebBmp.LockBits(New Rectangle(Point.Empty, WebBmp.Size), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb)
    15. Marshal.Copy(bd.Scan0, b, 0, b.Length)
    16. WebBmp.UnlockBits(bd)
    17. Dim movColor As Integer= ColorTranslator.FromHtml("#575C5F").ToArgb()
    18. For iMov As Integer = 0 To b.Length - 1
    19. If b(iMov) = movColorx Then
    20. X = iMov Mod WebBmp.Width
    21. Y = iMov \ WebBmp.Width
    22. movementfound = True
    23. Exit for
    24. else
    25. movementfound = False
    26. End If
    27. Next



    und dann mein timer

    VB.NET-Quellcode

    1. Private Sub Timer1_Tick(ByVal Sender As Object, ByVal e As EventArgs) Handles Timer1.Tick
    2. webLoc = PointToScreen(WebBrowser2.Location)
    3. webSiz = WebBrowser2.Size
    4. webLocThread1 = webLoc
    5. webSizThread1 = webSiz
    6. timer1starttr()
    7. If movementfound = True Then
    8. Label1.Text = "gefunden"
    9. Else
    10. Label1.Text = "nicht gefunden"
    11. End If

    Bildaufzeischnung läuft und maus hatt kein einfluß drauf.
    Jetzt muss ich schauen wie es mit den koordinaten übergabe aussieht x,y

    Was meint ihr dazu.

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „seby1302“ ()

    seby1302 schrieb:

    Was meint ihr dazu.
    Ein Thread ist dazu gemacht, in einer Endlosschleife permanent zu arbeiten.
    Um das ganze zu koordinieren, brauchst Du zwei Flags.
    Ein Flag, um den Thread zu beenden, der wird beendet, indem die Threadprozedur verlassen wird.
    Ein weiteres Flag, um dem Thread zu sagen, dass er tatsächlich was tun soll. Das kannst Du verbinden bit der Bereitstellung von Daten.
    So etwa:

    VB.NET-Quellcode

    1. Private FlagCancelThread As Boolean
    2. Private Sub Threadtimer1()
    3. FlagCancelThread = False ' wird von außen auf True gesetzt
    4. While True ' Thread-Endlosschleife
    5. If FlagCancelThread Then Return ' Thread beendet
    6. If FlagDoWork Then ' Wurde von außen auf True gesetzt
    7. FlagDoWork = False
    8. ' Hier das tun, was zu tun ist
    9. End If
    10. End While
    11. End Sub
    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!

    seby1302 schrieb:

    Also schreib mal erstmal die Methode so um, dass sie vom TimerTick aus aufgerufen wird, und dabei das zu fotografierende Rechteck übergeben wird.

    Gennau das ist grade mein problem.
    Ich hab das jetzt so gemacht
    [...]
    Was meint ihr dazu.
    Ich meine, dass du nicht zuhörst.
    Ich hab nicht gesagt, du sollst selbst versuchen, die Nebenläufigkeit zu implementieren - das weiß ich ja, dass dir die modernen Konzepte dafür nicht bekannt sind.
    Also schreib mal erstmal die Methode so um, dass sie vom TimerTick aus aufgerufen wird, und dabei das zu fotografierende Rechteck übergeben wird.
    Damit ist gemeint eine Methode, kein Threading.
    Einfach eine Methode, die tut was sie soll, und die hakelt und stockt, weil sie das ohne Threading macht.
    So eine Methode kann man mit leichtigkeit nebenläufig machen, nur muss sie erst einmal da sein.

    Aber wie mir deine Versuche aussehen, weisst du auch garnet, was mit "Methode" und "Argument" gemeint ist - jedenfalls hab ich von dir noch keine Methode gesehen, die Argumente erwartet.
    EventHandler-Methoden natürlich, aber die sind ja nicht von dir, sondern da haste auf ein Timer-Objekt gedoppelklickst, dann generiert Visualstudio die Methode mit Argumenten (das was bei Methoden inne erste Zeile inne Klammern steht).

    Vlt. guckst du dir mal Grundlagen: Fachbegriffe an.

    Und dann nochmal die Herausforderung lesen:
    Also schreib mal erstmal die Methode so um, dass sie vom TimerTick aus aufgerufen wird, und dabei das zu fotografierende Rechteck übergeben wird.
    Methode - klar?
    Argumente - klar?
    Welchen Datentyp müssen das/die Argument(e) haben, wenn sie "Rechteck" sein sollen?
    Ich sag vor: System.Drawing.Rectangle

    Aber jetzt müsste es doch möglich sein.
    Und gib der Methode einen sinnreichen Namen - Was tut die Methode? - so soll sie heissen.
    Meinst du das so?

    VB.NET-Quellcode

    1. Private Sub Threadtimer1(ByVal WebBmp As Bitmap, ByVal [b]b [/b]As Integer, ByVal bd As BitmapData)
    2. WebBmp = CaptureToBitmap(webLoc.X, webLoc.Y, webSiz.Width, webSiz.Height)
    3. b = (WebBmp.Width * WebBmp.Height - 1)
    4. bd = WebBmp.LockBits(New Rectangle(Point.Empty, WebBmp.Size), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb)


    Das hatte ich versucht habe damit aber 2 probleme.

    Problem numer 1:
    "Length " ist mein kein member von integer

    VB.NET-Quellcode

    1. For iMov As Integer = 0 To b.Length - 1



    Problem nr 2:
    Fehler BC30518 Fehler bei der Überladungsauflösung, da keine zugreifbare "New" mit diesen Argumenten aufgerufen werden kann:
    "Public Overloads Sub New(start As ThreadStart)": Die Signatur der Private Sub Threadtimer1(webBmp As Bitmap, b As Integer, bd As BitmapData)-Methode ist mit dem Delegaten "Delegate Sub ThreadStart()" nicht kompatibel.

    VB.NET-Quellcode

    1. Dim reload As Thread = New Thread(AddressOf Threadtimer1)
    2. reload.Start()



    Oder Verstehe ich jetzt wider nur Bahnhof

    ErfinderDesRades schrieb:

    Also schreib mal erstmal die Methode so um, dass sie vom TimerTick aus aufgerufen wird, und dabei das zu fotografierende Rechteck übergeben wird.
    Ich seh bei dir ühaupt keine Methode.
    Doch, eine, die heisst Threadtimer1 - aber die kanns ja nicht sein.
    Die Methode soll ja so heissen, wie was sie macht, aber was Threadtimer1 für eine Tätigkeit ist, wirst nichtmal du selbst wissen.
    Und ein Rechteck sollte ihr übergeben werden - davon sehe ich auch nichts.

    Guckma - so:

    VB.NET-Quellcode

    1. private Sub SaveScreenPartToFile(file as String, screenpart As Rectangle)
    2. '...
    3. End Sub
    Kann man ungefähr erahnen, was diese Methode tun wird?

    Oder so:

    VB.NET-Quellcode

    1. private Function FindColorOnScreen(color as Color, screenpart As Rectangle) As Boolean
    2. '...
    3. End Function
    Kann man ungefähr erahnen, was diese Methode tun wird?

    Und weil du scheints Schwierigkeiten hast, zu begreifen:
    Mach nichts mit Threading!

    Gar nichts!

    Das ist deutsch, und bedeutet: nichts - nichts machen mit Threads!

    Einfach - es nicht tun!

    nicht!!

    Threading - Nein - nicht!




    Nochmal zur Erinnerung, was wirklich ansteht:

    ErfinderDesRades schrieb:

    Also schreib mal erstmal die Methode so um, dass sie vom TimerTick aus aufgerufen wird, und dabei das zu fotografierende Rechteck übergeben wird.
    Reicht das, wenn ichs dir nun zum 5. Mal sage, oder wie oft brauchst du das?

    Oder vlt. noch simpler - schreib diese Methode fertig:

    VB.NET-Quellcode

    1. private Function FindColorOnScreen(color as Color, screenpart As Rectangle) As Boolean
    2. '...
    3. End Function
    Kriegst du das hin - ohne Threading? Ganz ohne? Kein System.Threading.Thread, kein Backgroundworker, kein Invoking?
    Einfach nur die Methode, so wie ich die Kopfzeile nu vorgegeben hab?

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

    seby1302 schrieb:

    Problem numer 1:
    "Length " ist mein kein member von integer
    Ich denke mal, Du solltest gaaaaanz weit vorn anfangen.
    Wovon genau willst Du die Länge bestimmen? Wie heißt die Variable, die eine Instanz dessen hält?
    Nimm Dir den Rat vom @ErfinderDesRades zu Herzen, mein Thread-Post war da doch etwas vorschnell.
    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!
    @seby1302: Versuch erst einmal die Methode FindColorOnScreen, wie sie @EDR vorgeschlagen hat, zu implementieren. Nur rein die Methode nix anderes: Kein Threading und kein BackgroundWorker.

    1.) Diese Methode rufst du zum Testen ein paar mal mit verschiedenen Eingabeparametern (wechsende Farbe, anderer Bereich) aber immer für das selbe Bild auf.
    2.) Wenn es klappt und dir immer richtige Ergebnisse geliefert werden, versuch mal die Methode mit der selben Farbe, dem selben Auschnitt auf mehrere verschiedene Bilder anzuwenden.
    3.) Wenn das auch hinhaut, kannst du versuchen verschiedene Farben in unterschiedlichen Ausschnitten und unterschiedlichen Bildern zu suchen.

    Jetzt kannst du dich daran machen (im Wissen, dass die Such-Methode das tut, was sie soll - und zwar egal mit welchen Eingabeparametern und egal auf welchen Bildern) dir den Inhalt des WebBrowser zu "screenshoten". Hier kannst du - sofern das grundlegend funktioniert - dich daran setzen und das ganze dann performance-technisch optimieren. Wenn das klappt, nur noch die Suche der Farbe in einen eigenen Thread packen (wie es @Rod schon gezeigt hat) und das Ganze in deinem GUI, in dem du den Browser abfotografierst, aufrufen und auswerten. Fertig!

    Das Abfotografieren und die Suche hast du - jedenfalls geh ich mal davon aus - schon funktionierenderweise implementiert => Ein (großer) Teil ist schon mal geschafft. Jetzt noch den Rest.

    Lg Radinator
    In general (across programming languages), a pointer is a number that represents a physical location in memory. A nullpointer is (almost always) one that points to 0, and is widely recognized as "not pointing to anything". Since systems have different amounts of supported memory, it doesn't always take the same number of bytes to hold that number, so we call a "native size integer" one that can hold a pointer on any particular system. - Sam Harwell

    Radinator schrieb:

    Wenn das klappt, nur noch ... in einen eigenen Thread packen (wie es @Rod schon gezeigt hat)
    Ja, und da rate ich von Rods Ansatz ab - der Async-Pattern ist einfacher und leistungsfähiger.
    Das würde ich ihm ja hinschreiben, ist ja u.U. nicht eine Zeile Code, sondern nur die richtigen Schlüsselworte an den richtigen STellen einfügen und feddich.

    Bei INteresse gugge
    codeproject.com/Articles/10296…ithout-any-additional-Lin

    ErfinderDesRades schrieb:

    Async-Pattern ist einfacher und leistungsfähiger.


    Wenn du mit "leistungsfähiger" unperformanter meinst, dann stimmt das. Auch wenn es in den meisten Fällen wirklich irrelevant ist und man natürlich je nach dem auch schafft mit Threads langsamer zu sein(nicht aber wenn mans richtig macht, dann wird man immer performanter - oder gleich - sein). Gibt es tatsächlich Fälle, bei denen man auf async verzichten sollte/muss...

    Aber ansonsten klar, ruhig immer verwenden, da es wie gesagt in den meisten Fällen irrelevant ist und der nutzen durch den besser lesbaren Code damit mehr Vorteile bringt...
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    Nein - "langsamer" meine ich nicht, wenn ich sage: "leistungsfähiger".

    Ich meine folgendes:
    Threading impliziert oft 5 Problemfelder:
    1. Gui Vor- und Nach-bereitung
    2. Nebenläufigkeit
    3. Gui-Aktualisierung während Nebenläufigkeit
    4. Exception-Handling
    5. Cancellation-Funktionalität
    Diese 5 Problemfelder kann man unter Verwendung des Async-Patterns deutlich eleganter versorgen als "mit Threads" - was immer du damit genau meinst (Async-Pattern geht ja auch mit Threads).

    Zur Performance weiß ich grad gar keine Tests oder verlässliche Aussagen zu Tests - ist dir da was bekannt?
    naja Implementierung eben, da sieht man ja wie das Implementiert wird und, da es quasi auch nur nen Wrapper ist kann man sich das z.B. schonmal sparen. bzw. dann Spezialisieren.
    Dann natürlich das typische State speichern, hat man quasi doppelt, einmal vom OS für die Threads(was aber zum Glück nur aufm Pool ist, also nur halb so wild) und dan nochmal für die einzelnen Methoden, das schlimmste dabei ist aber->
    Und über MemoryTracer. denn async macht gerne Heap Allocs, die man unter direkt Verwenung von Threads natürlich verhindern kann, weil man bereits selbst weiß, was genau man tut. C# kann das natürlich nicht Wissen(bzw. wäre möglich unter ziemlichem Compiler Aufwand - und zuvor sollten die .Net Compiler überhaupt mal richtig optimieren können :D).

    Also wie bereits gesagt trotz allem in den meisten Fällen irrelevant. Für GameDev jedoch sehr relevant, wenn da dann während des Renderings der GC anspringt ist immer unschön :D
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---