Link to home
Start Free TrialLog in
Avatar of romiebehunin
romiebehunin

asked on

VB.NET System.AccessViolationException: Attempted to read or write protected memory.

Hey guys... This has had me stumped all day so I figured I'd get some expert advise. I have a program that is doing some basic form screen scraping using API calls. Once I start reading in the various text elements on the child form, after about 10 iterations I get the following error:

System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
  at CaptureTextTest.Form1.EnumChildWindows(Int32 hWndParent, EnumChildWindProc lpEnumFunc, Int64 lParam)
  at CaptureTextTest.Form1.Button3_Click(Object sender, EventArgs e) in C:\... Form1.vb: line 140

I read that there was a hot fix for this issue: http://support.microsoft.com/?kbid=923028 but it does not seem applicable as I'm running .Net 3.5 SP1 on the machine in question. I've attached the code in full.

Option Strict Off
Option Explicit On
Imports System.Windows.Forms.Application
Imports System.Threading.Thread
Imports System.Runtime.InteropServices
Public Class Form1
    Public hWnd As Long
    Public obj As New TCaptureXLib.TextCaptureX
    Public strResults As String
    Public strWinTitle As String
    Public lhWndP As Long
    Public strCaption As String
    Public blnCustomScrape As Boolean
    Private strMyScrape As String

    

    <DllImport("user32", EntryPoint:="GetWindowTextLength")> _
Private Shared Function GetWindowTextLength( _
ByVal hwnd As Int32) As Int32
    End Function
    <DllImport("user32", EntryPoint:="FindWindow")> _
    Private Shared Function FindWindow( _
    ByVal lpClassName As String, _
    ByVal lpWindowName As String) As Int32
    End Function
    <DllImport("user32", EntryPoint:="GetWindowText")> _
    Private Shared Function GetWindowText( _
    ByVal hwnd As Int32, _
    ByVal lpString As System.Text.StringBuilder, _
    ByVal cch As Int32) As Int32
    End Function
    <DllImport("user32", EntryPoint:="GetWindow")> _
    Private Shared Function GetWindow( _
    ByVal hwnd As Int32, _
    ByVal wCmd As Int32) As Int32
    End Function
    Private Const GW_HWNDNEXT As Int32 = 2
    Private Declare Function BringWindowToTop Lib "user32" (ByVal _
         hwnd As Long) As Long
    Private Const WM_GETTEXT As Integer = &HD
    Private Const WM_GETTEXTLENGTH As Integer = &HE

    Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" _
            (ByVal hWnd1 As IntPtr, ByVal hWnd2 As IntPtr, ByVal lpsz1 As String, _
            ByVal lpsz2 As String) As Integer

    Private Declare Function SendMessage2 Lib "user32" Alias "SendMessageA" _
        (ByVal hWnd As IntPtr, ByVal wMsg As Integer, _
        ByVal wParam As Integer, ByVal lParam As Integer) As Integer

    Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
        (ByVal hWnd As IntPtr, ByVal wMsg As Integer, _
        ByVal wParam As Integer, ByVal lParam As System.Text.StringBuilder) As Integer

    Delegate Function EnumChildWindProc(ByVal hWnd As Int32, ByVal lParam As Long) As Boolean
    Declare Function EnumChildWindows Lib "user32" (ByVal hWndParent As Int32, ByVal lpEnumFunc As EnumChildWindProc, ByVal lParam As Long) As Long


    






    Private Sub CaptureWindow(ByVal hWnd)
        strResults = ""
        Do Until Not strResults = ""
            BringWindowToTop(hWnd)
            strResults = obj.CaptureActiveWindow()
            If strResults <> "" Then
                RichTextBox1.Text = strResults
            End If
            QuickRefresh(250)
        Loop
        'GetHandle()
    End Sub
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        RichTextBox1.Clear()
        GetHandle()
    End Sub
    Private Function GetHandleFromPartialCaption(ByRef lWnd As Long, ByVal sCaption As String) As Boolean
        GetHandleFromPartialCaption = False
        'Get the parent window using API
        lhWndP = FindWindow(vbNullString, vbNullString)
        'Get the child window here
        If lhWndP <> 0 Then

        End If
        Do While lhWndP <> 0
            Dim iStr As Integer = GetWindowTextLength(lhWndP) + 1
            Dim sStr As New System.Text.StringBuilder(iStr)
            GetWindowText(lhWndP, sStr, iStr)
            strCaption = sStr.ToString
            If InStr(1, strCaption, sCaption) > 0 Then
                GetHandleFromPartialCaption = True
                lWnd = lhWndP
                Exit Do
            End If
            lhWndP = GetWindow(lhWndP, GW_HWNDNEXT)
        Loop
    End Function
    Private Sub QuickRefresh(ByVal i As Integer)
        DoEvents()
        Sleep(i)
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        End
    End Sub
    Private Sub GetHandle()
        If GetHandleFromPartialCaption(lhWndP, "Practice Plus") = True Then
            'MsgBox("Found Window Handle: " & lhWndP, vbOKOnly + vbInformation)
            If blnCustomScrape = False Then
                CaptureWindow(lhWndP)
            End If
        Else
            MsgBox("Window 'Horizon' was not found", vbOKOnly + vbExclamation)
            End
        End If
        QuickRefresh(250)
    End Sub

    Private Function GetWindowText(ByVal hWnd As IntPtr) As String
        Dim textLength As Integer = SendMessage2(hWnd, WM_GETTEXTLENGTH, 0, 0) + 1
        Dim sb As New System.Text.StringBuilder(textLength)
        If textLength > 0 Then
            Call SendMessage(hWnd, WM_GETTEXT, textLength, sb)
        End If
        Return sb.ToString
    End Function

    Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        blnCustomScrape = True
        GetHandle()

        Try
            Dim proc As New EnumChildWindProc(AddressOf EnumChildWindow)
            Call EnumChildWindows(lhWndP, proc, 0&) 'This is the call that generates error

        Catch ex As Exception
            ex = ex
            MsgBox(ex.ToString)
            End
        End Try
    End Sub
    Function EnumChildWindow(ByVal hChild As Int32, ByVal lParam As Long) As Boolean

        Dim wText As New System.Text.StringBuilder(255)
        Dim j As Long
        j = GetWindowText(hChild, wText, 255)
        j = j
        'I get about 10 text elements from 
		'the child form before the error takes place
        strMyScrape = strMyScrape + wText.ToString
        EnumChildWindow = 1  ' Continue enumeration       
    End Function

End Class

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of Mike Tomlinson
Mike Tomlinson
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of romiebehunin
romiebehunin

ASKER

Yeah your right I added some delegates etc to convert some old VB6 stuff into this project... good suggestion I'll get to work on that shortly and then let you know if that solved the problem.
Excellent suggestion... did the trick!! Thank You!!