0

I am using the win32api to get a list of all window titles. I need the list to be refreshed every few seconds and thats the problem: The memory usage of the app is increasing every time I call EnumWindowsCallback.

Here is a working demo: Run the code and see in the task manager how the memory usage of this app increases. Press RETURN to call the function again.

Imports System.Runtime.InteropServices
Imports System.Text

Class Example
    Shared Sub Main()
        For a = 1 To 5
            Console.WriteLine("--------- (RUN NR " & a & ") PRESS RETURN")
            Console.ReadLine()
            Win32API.EnumWindowsDllImport(New Win32API.EnumWindowsCallback(AddressOf FillActiveWindowsList), 0)
        Next

        Console.WriteLine("READY!")
        Console.ReadLine()

    End Sub

    Shared Function FillActiveWindowsList(ByVal _hWnd As IntPtr, ByVal lParam As IntPtr) As Boolean
        Dim windowText As New StringBuilder(255)        
        Win32API.GetWindowText(_hWnd, windowText, 255)
        Console.WriteLine(windowText)
        Return True
    End Function

End Class

Public Class Win32API
    Public Delegate Function EnumWindowsCallback(hWnd As Integer, lParam As Integer) As Boolean

    <DllImport("user32.dll", EntryPoint:="EnumWindows", SetLastError:=True, CharSet:=CharSet.Ansi, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function EnumWindowsDllImport(callback As EnumWindowsCallback, lParam As Integer) As Integer
    End Function

    <DllImport("user32.dll", EntryPoint:="GetWindowTextA")> _
    Public Shared Sub GetWindowText(hWnd As Integer, lpstring As StringBuilder, nMaxCount As Integer)
    End Sub
End Class

at the beginning my EXE is about 3MB big, but after 5 function calls it is increased to 6 MB (and stays there) The problem is that it causes some crashes in my main application if the memory usage gets over 6 MB. The example above should not crash.

Do you see a problem here? Maybe there is a problem with the data types? or maybe it is a bug? Any help would be appreciated.

MilMike
  • 12,571
  • 15
  • 65
  • 82
  • 2
    If your app stays at 6MB it likely means that here is no leak. A leak will cause it to keep getting bigger. What are the exact _problems_ that you are experiencing in the main application? – Mike Dinescu Nov 11 '13 at 20:29
  • the problem is that the main app crashes if it gets over 6 MB in size. I am using also s lowlevel keyboard hook and this might cause the problem but I don't have the source code for the keyboard hook (dll). The app wont crash if it stays below 6 MB. I thought it is a win32api memory problem but I am not sure. – MilMike Nov 11 '13 at 21:10
  • Viewing the memory used value from Task Manager is a very unreliable way to detect memory leaks. More likely your app is crashing because you're not checking the return value of [GetWindowText](http://msdn.microsoft.com/en-us/library/windows/desktop/ms633520(v=vs.85).aspx). If it returns `false`, then `windowText` will be `null`, and you'll get a `NullReferenceException` when you try to output it. – Jim Mischel Nov 11 '13 at 21:36

2 Answers2

2

That's not possible, you won't get an OutOfMemoryException until you've consumed at least 1500 MB. You are a factor of x250 removed from explaining the "crash" with a leak. The 3 MB increase is simply the garbage collected heap growing to meet your program's demands. Seeing it stabilize is entirely normal as well, the ultimate hint that you don't have a leak.

Surely you get a better diagnostic than just "it crashed". You do have bugs in your code, the pinvoke declarations are wrong. The lParam arguments are IntPtr, not int. This can cause various amount of upheaval, you'd normally get a warning from the PInvokeStackImbalance Managed Debugger Assistant. Use the pinvoke.net website to get better ones. And do show in detail what that "crash" looks like in the debugger if you need more help.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • "OutOfMemoryException until you've consumed at least 1500 MB" Note to future readers that is not true for all cases, just the OP's case. Doing things like not handling your `IDisposeable`'s correctly on a object that pulls from a limited pool resources that do not put memory pressure on the GC, can cause a `OutOfMemoryException` to be thrown when plenty of memory is available. [Not disposing of `Graphics` objects and running out of GDI+ handles is a good example of this](http://stackoverflow.com/questions/6506089/system-drawing-out-of-memory-exception). – Scott Chamberlain Nov 11 '13 at 21:46
0

Replace This Code

For a = 1 To 5
    Console.WriteLine("--------- (RUN NR " & a & ") PRESS RETURN")
    Console.ReadLine()
    Win32API.EnumWindowsDllImport(New Win32API.EnumWindowsCallback(AddressOf FillActiveWindowsList), 0)
Next

with this code

dim a as integer = 1
DoitFive:
Console.WriteLine("--------- (RUN NR " & a & ") PRESS RETURN")
Console.ReadLine()
Win32API.EnumWindowsDllImport(New Win32API.EnumWindowsCallback(AddressOf FillActiveWindowsList), 0)
a += 1
if a <> 5 then goto DoitFive

Becouse the Code that you working with is holding the process of your EXE until loop 5 Times and that will make it 6MB Size.

Omar AlMA3lOl
  • 268
  • 2
  • 9