Morjens.
Miten voin kaapata kaiken tekstin toisen ohjelman ikkunasta? Onko mahdollista saada tietoon vielä tekstin väriä ja sijaintia ikkunassa?
Kerro millaista ratkaisua olet yrittänyt ja mihin on tyssännyt?
Mihin tarvitset tällaista?
Innostuin pitkästä aikaa nettipokerista ja ajatelin kokeilla tehdä eräänlaisen apuohjelman peliin. Pokeribotin koodaaminen on aina ollut haaveena, mutta ajattelin aloittaa homman tällaisella pienellä apuohjelmalla joka laskee mm potti- ja vetokertoimia ynnä pitää yllä pientä tilastoa.
Itse laskemisen ja tilastot pystyn luullakseni toteuttamaan helposti, mutta ongelma on pelitapahtumien lukeminen pelistä.
Käsittääkseni ainoa tapa selvittää pelin kulkua on näytön lukeminen. Softa kyllä ylläpitää logia aiemmista peleistä, mutta jos haluan reaaliaikaisen apuohjelman ei niillä tiedoilla tee oikeastaan mitään.
Jotain olen "kokeillut", mutta kun asia on uusi, outo ja kieli englanti, niin ajattelin kysyä apua suomalaisilta guruilta.
http://bytes.com/topic/visual-basic-net/answers/363935-extracting-text-another-application
http://social.msdn.microsoft.com/Forums/en-US/vbgeneral/thread/02a67f3a-4a26-4d9a-9c67-0fdff1428a66
http://www.codingthewheel.com/archives/how-i-built-a-working-poker-bot
Pokerisivusto on Pacific poker. Ja kuvia peli-ikkunasta löytää helposti Google kuvahaulla.
Onko peli java, flash vai mikä? Luultavasti joudut tekemään OCR:än tai sitten jonkin, joka osaa muistista lukea.. Vaikeaa joka tapauksessa.
Ruudulta lukeminen on kyllä vihoviimeinen idea. Yleispätevin ja usein helpoin ratkaisu on tehdä pelin verkkoprotokollan kanssa yhteensopiva oma peliklientti, joka siis keskustelee suoraan pelipalvelimen kanssa ja korvaa täysin alkuperäisen pelin. Jos peli pyörii suoraan selaimessa (HTML ja JS), vaihtoehtona on myös tehdä omat "laajennokset" JavaScriptilla ja lisätä ne sivulle esimerkiksi Firefoxissa Greasemonkey-lisäosalla, jolloin ne voivat lukea tietoja suoraan sivun lähdekoodista tai sivun JavaScriptin muista osista.
Joo nuo kortit on aika helppo tunnistaa vaikka GetPixelillä, Mutta en tiedä tuosta tekstikentästä. KOkeile GetText APIa,, se luultavasti toimii jos peli on html js pohjainen.
EDIT: jaa metabolix ehti jo väliin.. kirjotin tätä muutaman tunnin..
Moi novice!
elikä "Jos peli pyörii suoraan selaimessa" niin voit poimia HTML:stä vaikka näin
Imports System
Public Partial Class MainForm
   Public Sub New()
      Me.InitializeComponent()
   End Sub
   Sub WebBrowser1_DocumentCompleted(sender As Object, _
   e As WebBrowserDocumentCompletedEventArgs)
         Timer1.Interval = 500
         Timer1.Enabled = True
         Timer1.Start
   End Sub
   Sub MainForm_Shown(sender As Object, e As EventArgs)
      WebBrowser1.Url = _
      New Uri("https://www.ohjelmointiputka.net/morpion/peli.php")
   End Sub
   Sub Timer1_Tick(sender As Object, e As EventArgs)
      Timer1.Stop
      Static bodyTag As String
      Dim bodyStr As String = WebBrowser1.Document.Body.OuterHtml
      If bodyTag <> bodyStr Then
         textBox1.Clear
         Dim elems As HtmlElementCollection
         elems = WebBrowser1.Document.GetElementsByTagName("p")
         For i = 0 To elems.Count - 1
            Dim elemStr As String = elems.Item(i).InnerHtml.ToString
            'testi...
            If  elemStr.IndexOf("INPUT") = -1 And _
            elemStr.IndexOf("A href") = -1 Then
               textBox1.Text += elems.Item(i).InnerText _
               + Environment.NewLine
            End if
         Next
      End If
      bodyTag = bodyStr
      Timer1.Start
   End Sub
End ClassNea: Enpä usko että toi hyödyttää suurelti kun kyseessä on Flash-peli.
novice: protip: Sitä englantia kannattaa oikeasti opetella sillä kaikki hyvä matsku on englanniksi.
Itse olen koodannut jotain samanlaista C:llä flash-peliä varten, ja todennut viritelmäni toimivaksi. Käytän koodissani IWebBrowser2-interfacea, jolla kirjaudutaan peliin ja siirrytään pelisivulle. Pelisivulla tapahtuu flash-pelin (.swf-tiedosto) lataaminen ja pelaaminen. Jotta pystyn seuraamaan pelin tapahtumia, olen hookannut oman prosessin connect()-, send()- ja recv()-funktiot ws2_32.dll:stä. connnect-hookilla saan selville soketin, jonka kautta tapahtuu peliklientin keskustelu (tiedän että peli yrittää yhdistää porttiin 30000). Sen jälkeen vain seuraan sen soketin kautta kulkevaa nettiliikennettä ja reagoin siihen haluamallani tavalla.
Tämä on varmasti monelle vaikea lähestymistapa ongelmaan, mutta kohtuullisen vakaa ja pienitöinen verrattuna kokonaan oman peliklientin kirjoittamiseen. Jotain mahdollisia ongelmia kuitenkin on. Nettiliikenne voi olla salattu, pelin nettiprotokolla tulee ymmärtää, sekä kun peliä päivitetään se voi vaatia myös ohjelmasi päivittämistä. Nämä kaikki ongelmat on kuitenkin olemassa myös silloin, kun koodataan kokonaan oma klientti.
Et ole edes kertonut, toimiiko pelisi flashilla vai millä. Näytöltä lukeminen voi toimia ihan hyvin, jos se toteutetaan oikein. Kyse on pelkästään pokeripelistä, joten pelkkien korttien tunnistaminen ei pitäisi olla kohtuuttoman vaikeaa. Ei myöskään olisi kovin vaikeaa pyytää käyttäjää syöttämään ohjelmaan jaetut kortit, jolloin ohjelma toimisi mahdollisesti myös muiden samanlaisten pokeripelien kanssa.
edit. Jaahas, pacific poker kyseessä. Näyttäisi siltä ettei toimi flashilla, Toi mun ehdottama tapa toimii edelleenkin, joskin sen toteuttaminen on hieman vaikeampaa, koska funktiot tulee hookata etäprosessista. Kun kyseessä näyttää olevan tavallinen binäärisovellushärveli, niin yksi vaihtoehto olisi memory editorilla (cheat engine) selvittää missä kohtaa muistia tiedot korteista säilytetään ja lukea ne sieltä. Voi olla vaikeaa jos ei ole ennen säätänyt tällaisia juttuja. Se olisi helppo ja varma tapa, mutta sitäkin joutuisi päivittelemään kun peliä päivitetään.
Peli ei pyöri selaimessa vaan on käsittääkseni ihan tavallinen koneelle asennettava windows sovellus (en kyllä ole yhtään varma).
Itse korttien lukeminen näytöltä pikselitarkistusena ei ole ongelma, vaan muiden pelaajien toimintojen selvittäminen. Esim. ketä on pelissä mukana, paljonko pelaajalla on rahaa, maksoiko/luovuttiko/vai korottiko pelaaja, paljonko potissa on rahaa, yms.
Tuli yllättävä meno en ehtinyt kirjoittaa viestiä valmiiksi asti...
Yritin seuraavaa koodia tekstin kaappaamiseen:
'Formille 2 buttonia, label ja 2 listboxia
Public Class Form1
    Dim WindowsStuff As Class1 = New Class1
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        ListBox1.Items.Clear()
        WindowsStuff.GetActiveWindows()
        For Each AW In WindowsStuff.ActiveWindowList
            ListBox1.Items.Add(AW.ToString & vbTab & WindowsStuff.GetWindowsText(AW))
        Next
    End Sub
    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        ListBox2.Items.Clear()
        Dim SelectedhWnd As IntPtr
        If ListBox1.SelectedIndex <> -1 Then
            SelectedHwnd = WindowsStuff.ActiveWindowList(ListBox1.SelectedIndex)
            Label2.Text = WindowsStuff.GetWindowsText(SelectedHwnd)
        Else
            Exit Sub
        End If
        WindowsStuff.GetChildWindows(SelectedhWnd)
        For Each item In WindowsStuff.ChildWindowList
            ListBox2.Items.Add(item.ToString & vbTab & WindowsStuff.GetWindowsText(item))
        Next
    End Sub
End ClassImports System.Runtime.InteropServices
Public Class Class1
    Public Declare Function EnumChildWindows Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal adress As CallBack, ByVal lParam As Integer) As Boolean
    Public Declare Function EnumWindows Lib "user32.dll" (ByVal Adress As CallBack, ByVal lparam As Integer) As Integer
    Public Delegate Function CallBack(ByVal hWnd As IntPtr, ByVal lParam As IntPtr) As Boolean
    Private Const WM_GETTEXT As Integer = &HD
    Declare Auto Function SendMessage Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, ByVal lParam As String) As IntPtr
    Public Declare Function IsWindowVisible Lib "user32.dll" (ByVal hWnd As IntPtr) As Boolean
    Public ChildWindowList As List(Of IntPtr)
    Public ActiveWindowList As List(Of IntPtr)
    Public Function GetChildWindows(ByVal ParentHandle As IntPtr)
        ChildWindowList = New List(Of IntPtr)
        Dim ListHandle As GCHandle = GCHandle.Alloc(ChildWindowList)
        EnumChildWindows(ParentHandle, AddressOf EnumChildWindowList, GCHandle.ToIntPtr(ListHandle))
        Return ChildWindowList.ToArray
    End Function
    Public Function GetActiveWindows()
        ActiveWindowList = New List(Of IntPtr)
        EnumWindows(AddressOf EnumActiveWindowList, 0)
        Return ActiveWindowList.ToArray
    End Function
    Private Shared Function EnumChildWindowList(ByVal hWnd As IntPtr, ByVal lParam As integer) As Boolean
        Dim ChildWindowList As List(Of IntPtr) = GCHandle.FromIntPtr(lParam).Target
        ChildWindowList.Add(hWnd)
        Return True
    End Function
    Private Function EnumActiveWindowList(ByVal hWnd As IntPtr, ByVal lParam As Integer) As Boolean
        If IsWindowVisible(hWnd) Then
            ActiveWindowList.Add(hWnd)
        End If
        Return True
    End Function
    Public Function GetWindowsText(ByVal hWnd As IntPtr)
        Dim Name As String = Space(100)
        Dim NumText As Integer = SendMessage(hWnd, WM_GETTEXT, 50, Name)
        Return Trim(Name)
    End Function
End ClassEn täysin ymmärrä mitä yllä olevassa koodissa tapahtuu, mutta pokeripeli-ikkunasta se ei löydä kuin kuusi childwindowia joista vain yhdestä (chatruutu) löytyy tekstiä.
Peli-ikkunassa kuitenkin on tekstiä, miten sen saisi kaapattua?
Deffi kirjoitti:
...niin yksi vaihtoehto olisi memory editorilla (cheat engine) selvittää missä kohtaa muistia tiedot korteista säilytetään ja lukea ne sieltä. Voi olla vaikeaa jos ei ole ennen säätänyt tällaisia juttuja.Se olisi helppo ja varma tapa, mutta sitäkin joutuisi päivittelemään kun peliä päivitetään.
Olipa tapa mikä hyvänsä, joutuu sitä luultavasti aina päivittämään pelipäivityksen jälkeen.
novice kirjoitti:
Softa kyllä ylläpitää logia aiemmista peleistä...
Voisiko tuon login tulevan lisäyksen jotenkin kaapata muistista, tai jostain...?
Deffi kirjoitti:
Kun kyseessä näyttää olevan tavallinen binäärisovellushärveli, niin yksi vaihtoehto olisi memory editorilla (cheat engine) selvittää missä kohtaa muistia tiedot korteista säilytetään ja lukea ne sieltä.
Cheat engine! Sillähän nuo tekstit näytti löytyvän (nopeasti vain kokeilin). Pitääpä alkaa reenaileen tuota muistista lukemista....
Saatko Spy++:lla tarkasteltua ikkunan tekstejä? Jos saat niin APEja hyödyntämällä kaappaus kyllä onnistuu..
Epäilen tosin suuresti jos kyseessä on flash peli.
JussiR kirjoitti:
Saatko Spy++:lla tarkasteltua ikkunan tekstejä? Jos saat niin APEja hyödyntämällä kaappaus kyllä onnistuu..
Epäilen tosin suuresti jos kyseessä on flash peli.
WinSpy lienee samankaltainen ohjelma. löydän sillä kyllä jakajan chat-ruudun, mutta en muuta.
Tyhmä kysymys; Mistä tietää onko peli flash tai jotain muuta?
novice kirjoitti:
Tyhmä kysymys; Mistä tietää onko peli flash tai jotain muuta?
Paina pelin päällä hiiren oikeaa nappia ja katso onko siinä menussa kohta "About Abobe Flash Player" tai muuta Flashiin viittaavaa.
Morjens taas novice!
Mikäli mielenkiintoa vielä riittää niin tässä esimerkki-viritelmä,
joka hyödyntää Local Shared Object eli flash cookies kamaa...
Imports System
Imports System.IO
Imports mshtml
Public Partial Class MainForm
   Private basePath As String = String.Empty
   Private sourcePath As String = String.Empty
   Private tempPath As String = String.Empty
    Public Sub New()
      Me.InitializeComponent()
   End Sub
   Sub MainForm_Load(sender As Object, e As EventArgs)
      If   CheckInstances(Me.Text) Then
         Me.Dispose(): End
      End If
   End Sub
   Sub WebBrowser1_DocumentCompleted(sender As Object, _
   e As WebBrowserDocumentCompletedEventArgs)
         Timer1.Interval = 500: Timer1.Enabled = True: Timer1.Start
   End Sub
   Sub MainForm_Shown(sender As Object, e As EventArgs)
      WebBrowser1.Url = _
      New Uri("http://content.funny-games.biz/governor-of-poker-2.swf")
   End Sub
   Sub Timer1_Tick(sender As Object, e As EventArgs)
      If webBrowser1.ReadyState <> 4 Then
         Exit Sub
      End If
      Application.DoEvents
      Timer1.Stop
      Dim CurrentDocument As MSHTML.IHTMLDocument2 = _
      CType(WebBrowser1.Document.DomDocument, IHTMLDocument2)
      Dim embeds As IHTMLElementCollection = CurrentDocument.embeds
      If embeds.length > 0 Then
         If basePath = String.Empty Then
            Dim AppDataPath As String = Environment.GetFolderPath( _
            Environment.SpecialFolder.ApplicationData)
            AppDataPath += _
            "\Macromedia\Flash Player\#SharedObjects\33MMP4KX\"
            Dim sourceInfo As New DirectoryInfo(AppDataPath)
            For Each subDir As DirectoryInfo In sourceInfo.GetDirectories
               If subDir.Name.IndexOf(WebBrowser1.Url.Host) > -1 Then
                  'Käytä kerrallaan vain yhtä pelaajaprofiilia...
                  'Mikäli luot uuden profiilin niin muista poistaa
                  'flas-pelin listalta mahdollinen aiempi profiili.
                  Dim files() As FileInfo = _
                  subDir.GetFiles("Governor_of_Poker2_v100_demo_*")
                  If files.length > 0 Then
                     sourcePath = subDir.FullName + _
                     "\" + files(0).ToString
                     tempPath = Environment.GetFolderPath( _
                     Environment.SpecialFolder.Desktop)
                     tempPath += "\" + files(0).ToString
                  End if: Exit For
               End If
            Next
            sourceInfo = Nothing: AppDataPath = Nothing
         End If
         If sourcePath <> String.Empty Then
            FileCopy(sourcePath,tempPath)
            Do While Dir(tempPath) = ""
            Application.DoEvents: Loop
            Dim strFile As String
            Dim MyChar As Char() = CType("pokerGame:", Char())
            FileOpen(1, tempPath, OpenMode.Input, OpenAccess.Read)
            strFile = InputString(1, CType(LOF(1), Integer))
            FileClose(1): Dim pos As Integer = _
            strFile.IndexOf("pokerGame:")
            'Testi (tutki kamaa ja väännä itse oma parseri)...
            Try
               textBox1.Text = _
               strFile.Substring(pos, strFile.Length - pos)
            Catch ex As Exeption
               sourcePath = String.Empty
            End Try
            Kill(tempPath): strFile = Nothing
         End If
      End If
      Timer1.Start
   End Sub
   Private Function CheckInstances(ByVal AppName As String) As Boolean
      Dim MyProcess As Process() = _
      Process.GetProcessesByName(AppName)
      Dim IsAllReadyRunnig As Boolean
      If Not MyProcess Is Nothing Then
          If MyProcess.Length   > 1 Then
         IsAllReadyRunnig = True
      Else
         IsAllReadyRunnig = False
      End If
      End If
      MyProcess = Nothing
      Return IsAllReadyRunnig
   End Function
   Sub MainForm_FormClosing(sender As Object, e As FormClosingEventArgs)
      Try
         Timer1.Stop
      Catch ex As Exception
      End Try
      Timer1.Enabled = False
      Me.Dispose()
   End Sub
   Sub MainForm_FormClosed(sender As Object, e As FormClosedEventArgs)
      End
   End Sub
End Classmanne kirjoitti:
Itsekin olen kiinnostunut tästä muistista lukemisesta, mutta ainakin omissa peleissä nuo tietojen sijainnit muistissa vaihtuvat jokaisella pelin käynnistyskerralla. Onko tähän mitään muuta ratkaisua kuin skannata muisti joka kerralla uudestaan?
Kutsutaan DMA:ksi (dynamic memory allocation) ja tämän kiertämiseksi on pari tapaa. Voit etsiä osoittimen joka osoittaa haluaamaasi tietoon. Tietosi voi olla esimerkiksi osa jotain luokkaa/struktuuria, jolloin osoitin ei osoita suoraan haluaamaasi kohtaan, vaan struktin alkuun. Toivon mukaan sitten kun löydät osoittimen, niin se säilytetään aina samassa kohtaa muistia (vaikka peli käynnistettäisiin uudelleen). Sitten pääset haluamaasi tietoon käsiksi lukemalla ensiksi osoittimen arvon ja muokkaamalla osoittimen osoittamaa kohtaa. Joo...
Käyttämällä vaikka Cheat Engineen sisäänrakennettua debuggeria saat selville, missä kohtaa muistia arvoasi käsitellään. Tästä voit tutkia (jos osaat assemblyä) kuinka peli pääsee käsiksi tietoosi, ja käyttää itse samaa tapaa. Toinen vaihtoehto on käyttää code injectioniksi kutsuttua tapaa. Kun tiedät missä arvoasi käsitellään, voit muokata sitä kohtaa ohjelmasta haluamaksesi. Yleensä kirjotetaan hyppy-käsky johonkin omaan pätkään koodia, mikä sitten tekee jotain taikatemppuja. Vaatii jonkinlaista ymmärrystä assemblystä tämäkin.
Jostain syystä hyvien tutoriaalien löytäminen aiheesta (defeating DMA) on nykyään vaikeaa. Kymmenen vuotta sitten gamehacking-skene vielä kukoisti ;-( Cheat Enginen mukana taitaa tulla tutorial.exe, jossa sivutaan näitä ja monia muita hyödyllisiä aiheita.
Morjens taas!
tässä vielä eräs mahdollisuus moisen viritelmän vääntämiseksi...
'EmbedSwfSpy.exe (Väännetty SharpDevelop 4.0 Beta 2:lla)
'Ohjausobjektit:
'Paneeli  (panel1), WebBrowser (webBrowser1) & Labelli (label1)
'(WebBrowser-kontrolli paneelin sisälle)
Imports System
Imports System.Runtime.InteropServices
Imports Accessibility '(Accessibility.dll)
Imports AccLayer '(AccLayer.dll) [linkki "http://www.tuubi.net/neansivut/downloads/AccLayer.zip"]löytyy täältä[/linkki]
Imports mshtml  '(Microsoft.mshtml.dll saatavilla Office PIAs-paketissa)
'PIAs Office XP:lle [linkki "http://www.microsoft.com/downloads/en/details.aspx?FamilyID=c41bd61e-3060-4f71-a6b4-01feba508e52&DisplayLang=en"]löytyy täältä[/linkki]
'PIAs Office 2003:lle [linkki "http://www.microsoft.com/downloads/en/details.aspx?familyid=3C9A983A-AC14-4125-8BA0-D36D67E0F4AD&displaylang=en"]löytyy täältä[/linkki]
'PIAs Office 2007:lle [linkki "http://www.microsoft.com/downloads/en/details.aspx?FamilyID=59daebaa-bed4-4282-a28c-b864d8bfa513&displaylang=en"]löytyy täältä[/linkki]
'PIAs Office 2010:lle [linkki "http://www.microsoft.com/downloads/en/details.aspx?FamilyID=5d57c998-b630-4f38-afaa-b79747a3da06"]löytyy täältä[/linkki]
Public Partial Class MainForm
   Private MyAccObject As IAccessible = Nothing
   Private AccNodeObject As IAccessible = Nothing
   Public Sub New()
      Me.InitializeComponent()
   End Sub
   Sub MainFormLoad(sender As Object, e As EventArgs)
      If  CheckInstances(Me.Text) Then
         Me.Dispose(): End
      End If
      Me.AccessibleName = "SwfSpyMainForm"
      Me.AccessibleRole = AccessibleRole.Window
      Me.webBrowser1.AccessibleName ="BrowserWindow"
      Me.webBrowser1.AccessibleRole = AccessibleRole.Window
      Me.panel1.AccessibleName = "BrowserPane"
      Me.panel1.AccessibleRole = AccessibleRole.Pane
      Me.label1.AccessibleName = "DataLabel"
      Me.label1.AccessibleRole = AccessibleRole.Window
   End Sub
   Sub MainFormShown(sender As Object, e As EventArgs)
      WebBrowser1.Url = _
      New Uri("http://content.funny-games.biz/governor-of-poker-2.swf")
   End Sub
   Sub WebBrowser1DocumentCompleted(sender As Object, _
   e As WebBrowserDocumentCompletedEventArgs)
      MyAccObject = Nothing
      Dim CurrentDocument As MSHTML.IHTMLDocument2 = _
      CType(WebBrowser1.Document.DomDocument, IHTMLDocument2)
      Dim embeds As IHTMLElementCollection = CurrentDocument.embeds
      If embeds.length > 0 Then
         Dim mother As IAccessible = _
         Acc.GetAccessibleObjectFromHandle(webBrowser1.Handle)
         If mother IsNot Nothing Then
            Dim children As Object() = _
            Acc.GetAccessibleChildren(mother)
            If children.Length > 0 Then
               For i As Integer = 0 To children.GetUpperBound(0)
                  Dim child As IAccessible = _
                  CType(children(i), IAccessible)
                  If child.accName = "BrowserWindow" Then
                     'kotrollien 'solmut' on etsitty:
                     'AccExplorer32.exe - ohjelmalla [linkki "http://www.expertti.comyr.com/downloads/AccEvent32.zip"]löytyy täältä[/linkki]
                     Erase children: children = _
                     Acc.GetAccessibleChildren(child)
                     child = CType(children(0), IAccessible)
                     Erase children: children = _
                     Acc.GetAccessibleChildren(child)
                     child = CType(children(3), IAccessible)
                     Erase children: children = _
                     Acc.GetAccessibleChildren(child)
                     child = CType(children(0), IAccessible)
                     Erase children: children = _
                     Acc.GetAccessibleChildren(child)
                     child = CType(children(3), IAccessible)
                     Erase children: children = _
                     Acc.GetAccessibleChildren(child)
                     child = CType(children(0), IAccessible)
                     If child.accName = webBrowser1.Url.ToString Then
                        AccNodeObject = child: child = Nothing
                        children = Nothing: mother = Nothing
                     End If: Exit For
                  End If
               Next i
            End If
            If AccNodeObject IsNot Nothing Then
               timer1.Interval = 250: timer1.Enabled = True: timer1.Start
            End If
         End If
      End If
   End Sub
   Sub Timer1Tick(sender As Object, e As EventArgs)
      If webBrowser1.ReadyState <> 4 Then
         Exit Sub
      End If
      If MyAccObject Is Nothing Then
         Dim children As Object() = _
         Acc.GetAccessibleChildren(AccNodeObject)
         Dim child As IAccessible = Nothing
         child = CType(children(0), IAccessible)
         Erase children: children = _
         Acc.GetAccessibleChildren(child)
         child = CType(children(0), IAccessible)
         Erase children: children = _
         Acc.GetAccessibleChildren(child)
         MyAccObject = CType(children(3), IAccessible)
         AccNodeObject = Nothing
      Else
         Dim MyChildren As Object() = _
         Acc.GetAccessibleChildren(MyAccObject)
         'Dim MyPointer As IntPtr = IntPtr.Zero: label1.Text = ""
         For i As Integer = 0 To MyChildren.GetUpperBound(0)
            Dim MyChild As IAccessible = Nothing
            Try
               MyChild = CType(MyChildren(i), IAccessible)
            Catch ex As Exception
            End Try
            If Not MyChild Is Nothing Then
               If MyChild.ToString = "System.__ComObject" Then
                  Try
                     MyChild.accHitTest(1, 1)
                  Catch ex As Exception
                  End Try
                  Try
                     'koska tämä tökkii...
                     'Dim MyProperties As AccPropertySet = _
                     'New AccPropertySet(MyChild)
                     'label1.Text = MyProperties.Value
                     'ja tämä tökkii...
                     'Dim MyProperties As AccPropertySet = _
                     'New AccPropertySet(MyChild)
                     'MyPointer=Marshal.GetIUnknownForObject(MyProperties)
                     'label1.Text += Marshal.PtrToStringAuto(MyPointer)
                     'niin päätin lukea suoraan liittymästä...
                     MyPointer = Marshal.GetIUnknownForObject(MyChild)
                     label1.Text += Marshal.PtrToStringAuto(MyPointer)
                     'elikä jos joku keksii keinon parsia dataa tai
                     'lukea muistia paremmin niin antakoon palaa...
                  Catch ex As Exception
                  End Try
               End If
            End If
         Next
         If MyPointer <> IntPtr.Zero Then
            Dim MyRefCount As Integer = Marshal.Release(MyPointer)
         End If
      End If
      timer1.Start
   End Sub
   Private Function CheckInstances(ByVal AppName As String) As Boolean
      Dim MyProcess As Process() = _
      Process.GetProcessesByName(AppName)
      Dim IsAllReadyRunnig As Boolean
      If Not MyProcess Is Nothing Then
          If MyProcess.Length   > 1 Then
            IsAllReadyRunnig = True
         Else
            IsAllReadyRunnig = False
      End If
      End If
      MyProcess = Nothing
      Return IsAllReadyRunnig
   End Function
   Sub MainFormFormClosing(sender As Object, e As FormClosingEventArgs)
      Try
         Timer1.Stop
      Catch ex As Exception
      End Try
      Timer1.Enabled = False
      Me.Dispose()
   End Sub
   Sub MainFormFormClosed(sender As Object, e As FormClosedEventArgs)
      End
   End Sub
End ClassAihe on jo aika vanha, joten et voi enää vastata siihen.