Results 1 to 16 of 16

Thread: [RESOLVED] Can't Loop Through Items in a Collection

  1. #1

    Thread Starter
    New Member
    Join Date
    Apr 2010
    Posts
    12

    Resolved [RESOLVED] Can't Loop Through Items in a Collection

    CAUTION: Noob using Win32 API ahead

    I want to display a list of open windows on my computer in a rich text box. So, I'm trying to store the names of all windows in myString, and then set RichTextBox1.Text = myString.

    Here's the code

    Code:
    Imports System
    Imports System.Collections.Generic
    Imports System.Collections.ObjectModel
    Imports System.Text
    
    Public Class Form1
        Private Function Display(ByVal cs As Collection(Of String))
            Dim builder As New StringBuilder
            For Each item As String In cs
                builder.Append(item & vbCrLf)
            Next item
            Return builder.ToString
        End Function
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    
            RichTextBox1.Text = Display(GetActiveWindows)
    
        End Sub
    
        ' CallBack delegate    
        Public Delegate Function CallBack(ByVal hWnd As IntPtr, ByVal lParam As Integer) As Boolean
    
        ' Imports
        Public Declare Function EnumWindows Lib "user32" (ByVal Adress As CallBack, ByVal y As Integer) As Integer
        Public Declare Function IsWindowVisible Lib "user32" (ByVal hwnd As IntPtr) As Boolean
        Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Integer, ByVal lpWindowText As String, ByVal cch As Integer) As Integer
        ' /Imports
    
        Private ActiveWindows As New Collection(Of String)
    
        Public Function GetActiveWindows() As Collection(Of String)
            ActiveWindows.Clear()
            EnumWindows(AddressOf Enumerator, 0)
            Return ActiveWindows
        End Function
    
        Private Function Enumerator(ByVal hwnd As IntPtr, ByVal lParam As Integer) As Boolean
            Dim text As String = Space(Int16.MaxValue)
            GetWindowText(hwnd, text, Int16.MaxValue)
            If IsWindowVisible(hwnd) Then
                ActiveWindows.Add(text)
            End If
            Return True
        End Function
    End Class
    So, Display function above doesn't loop through the Collection of window titles. I don't know why. I just need to know why for educational purposes. I managed to display the list of window titles in the rich text box using another method...shown below.

    Thanks,

    Code:
    Imports System
    Imports System.Collections.Generic
    Imports System.Collections.ObjectModel
    Imports System.Text
    
    Public Class Form1
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            For Each item As String In GetActiveWindows()            
                RichTextBox1.AppendText(item)
                RichTextBox1.AppendText(vbCrLf)
            Next
            'RichTextBox1.Text
    
        End Sub
    
        ' CallBack delegate    
        Public Delegate Function CallBack(ByVal hWnd As IntPtr, ByVal lParam As Integer) As Boolean
    
        ' Imports
        Public Declare Function EnumWindows Lib "user32" (ByVal Adress As CallBack, ByVal y As Integer) As Integer
        Public Declare Function IsWindowVisible Lib "user32" (ByVal hwnd As IntPtr) As Boolean
        Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Integer, ByVal lpWindowText As String, ByVal cch As Integer) As Integer
        ' /Imports
    
        Private ActiveWindows As New Collection(Of String)
    
        Public Function GetActiveWindows() As Collection(Of String)
            ActiveWindows.Clear()
            EnumWindows(AddressOf Enumerator, 0)
            Return ActiveWindows
        End Function
    
        Private Function Enumerator(ByVal hwnd As IntPtr, ByVal lParam As Integer) As Boolean
            Dim text As String = Space(Int16.MaxValue)
            GetWindowText(hwnd, text, Int16.MaxValue)
            If IsWindowVisible(hwnd) Then
                ActiveWindows.Add(text)
            End If
            Return True
        End Function
    End Class

  2. #2
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    40,106

    Re: Can't Loop Through Items in a Collection

    Since you claim to be new, are you familiar with breakpoints and stepping through code? Since you want to figure it out for educational purposes, a motivation that I thoroughly applaud, the best way to learn it is to figure it out yourself, and stepping through that loop would be the way to go.

    Put a breakpoint on the For line of the loop. When execution pauses at the breakpoint, take a look at the collection (either hover over it, or use Shift+F9 on it) and see whether there are any items in it. Then step through the loop watching what happens in the stringbuilder. Frankly, I think you will find that the collection is empty, as the rest looks reasonable. The next step, then, would be to go figure out why the collection is empty, but this is a start.
    My usual boring signature: Nothing

  3. #3

    Thread Starter
    New Member
    Join Date
    Apr 2010
    Posts
    12

    Re: Can't Loop Through Items in a Collection

    Actually, the Collection isn't empty. It contains 15 items in my case. And as I watch the code executes, I see that the code inside the loop is iterated 15 times, each time item has the value that it should and that value seems to be appended to builder, but for some reason the final value of the StringBuilder isn't output'd correctly on the rich text box.

  4. #4
    Hyperactive Member The Fire Snake's Avatar
    Join Date
    Sep 2009
    Location
    USA
    Posts
    401

    Re: Can't Loop Through Items in a Collection

    Where are you using string builder???
    Remember to click on the scales to the left and rep me if I helped

  5. #5

    Thread Starter
    New Member
    Join Date
    Apr 2010
    Posts
    12

    Re: Can't Loop Through Items in a Collection

    Quote Originally Posted by The Fire Snake View Post
    Where are you using string builder???
    Inside Display function.

  6. #6
    PowerPoster techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,687

    Re: Can't Loop Through Items in a Collection

    Turn on Option Explicit and turn on Option Strict... Display doesn't return a string... it returns an object...
    Private Function Display(ByVal cs As Collection(Of String))
    SHOULD BE
    Private Function Display(ByVal cs As Collection(Of String)) As String

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  7. #7

    Thread Starter
    New Member
    Join Date
    Apr 2010
    Posts
    12

    Re: Can't Loop Through Items in a Collection

    Quote Originally Posted by techgnome View Post
    Turn on Option Explicit and turn on Option Strict... Display doesn't return a string... it returns an object...
    Private Function Display(ByVal cs As Collection(Of String))
    SHOULD BE
    Private Function Display(ByVal cs As Collection(Of String)) As String

    -tg
    I changed the code as you suggested, but the problem persists.

    Code:
    Option Explicit On
    Option Strict On
    Imports System
    Imports System.Collections.Generic
    Imports System.Collections.ObjectModel
    Imports System.Text
    
    Public Class Form1
        Private Function Display(ByVal cs As Collection(Of String)) As String
            Dim builder As New StringBuilder
            For Each item As String In cs
                builder.Append(item & vbCrLf)
            Next item
            Return builder.ToString
        End Function
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    
            RichTextBox1.Text = Display(GetActiveWindows)
    
        End Sub
    
        ' CallBack delegate    
        Public Delegate Function CallBack(ByVal hWnd As IntPtr, ByVal lParam As Integer) As Boolean
    
        ' Imports
        Public Declare Function EnumWindows Lib "user32" (ByVal Adress As CallBack, ByVal y As Integer) As Integer
        Public Declare Function IsWindowVisible Lib "user32" (ByVal hwnd As IntPtr) As Boolean
        Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As System.IntPtr, ByVal lpWindowText As String, ByVal cch As Integer) As Integer
        ' /Imports
    
        Private ActiveWindows As New Collection(Of String)
    
        Public Function GetActiveWindows() As Collection(Of String)
            ActiveWindows.Clear()
            EnumWindows(AddressOf Enumerator, 0)
            Return ActiveWindows
        End Function
    
        Private Function Enumerator(ByVal hwnd As IntPtr, ByVal lParam As Integer) As Boolean
            Dim text As String = Space(Int16.MaxValue)
            GetWindowText(hwnd, text, Int16.MaxValue)
            If IsWindowVisible(hwnd) Then
                ActiveWindows.Add(text)
            End If
            Return True
        End Function
    End Class

  8. #8
    PowerPoster techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,687

    Re: Can't Loop Through Items in a Collection

    I'm a little confused why you have it setup but, hey, what ever....

    If you breakpoint on this line:
    Return builder.ToString

    What does Builder have?

    Does it have what you expect it to?

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  9. #9

    Thread Starter
    New Member
    Join Date
    Apr 2010
    Posts
    12

    Re: Can't Loop Through Items in a Collection

    Quote Originally Posted by techgnome View Post
    I'm a little confused why you have it setup but, hey, what ever....

    If you breakpoint on this line:
    Return builder.ToString

    What does Builder have?

    Does it have what you expect it to?

    -tg
    In QuickWatch, StringBuilder has four attributes(?)

    Capatcity = 524304
    Chars = In order to evaluate an indexed property, the property must be qualified and the arguments must be explicitly supplied by the user.
    Length = 458766
    MaxCapacity = 2147483647

    I'm not sure if it should have something else?

  10. #10
    PowerPoster techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,687

    Re: Can't Loop Through Items in a Collection

    Consider this:
    Code:
    Option Explicit On
    Option Strict On
    Imports System
    Imports System.Collections.Generic
    Imports System.Collections.ObjectModel
    Imports System.Text
    
    Public Class Form1
        Private Function Display(ByVal cs As Collection(Of String)) As String
            Dim builder As New StringBuilder
            For Each item As String In cs
                builder.Append(item & vbCrLf)
            Next item
            Return builder.ToString
        End Function
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim windowText As String = ""
    
            GetActiveWindows 
            windowText = Display(ActiveWindows) 'Breakpoint here... does AcvtiveWinows have what you expect?
            RichTextBox1.Text = windowText 'Breakpoint here, does windowText have what you expect?
    
        End Sub
    
        ' CallBack delegate    
        Public Delegate Function CallBack(ByVal hWnd As IntPtr, ByVal lParam As Integer) As Boolean
    
        ' Imports
        Public Declare Function EnumWindows Lib "user32" (ByVal Adress As CallBack, ByVal y As Integer) As Integer
        Public Declare Function IsWindowVisible Lib "user32" (ByVal hwnd As IntPtr) As Boolean
        Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As System.IntPtr, ByVal lpWindowText As String, ByVal cch As Integer) As Integer
        ' /Imports
    
        Private ActiveWindows As New Collection(Of String)
    
        Public Sub GetActiveWindows() 
            ActiveWindows.Clear()
            EnumWindows(AddressOf Enumerator, 0)
        End Function
    
        Private Function Enumerator(ByVal hwnd As IntPtr, ByVal lParam As Integer) As Boolean
            Dim text As String = Space(Int16.MaxValue)
            GetWindowText(hwnd, text, Int16.MaxValue)
            If IsWindowVisible(hwnd) Then
                ActiveWindows.Add(text)
            End If
            Return True
        End Function
    End Class
    Re-arranged a few things...

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  11. #11

    Thread Starter
    New Member
    Join Date
    Apr 2010
    Posts
    12

    Re: Can't Loop Through Items in a Collection

    Quote Originally Posted by techgnome View Post
    Consider this:
    Code:
    ...
    Re-arranged a few things...

    -tg
    Thanks for that, techgnome.

    Yes, ActiveWindows does have what I expect. windowText, on the other hand, only contains the name of the first window in the Collection (Apologize for forgetting to mention this earlier. Printing only the name of the first window in the Collection has always been the case).

  12. #12
    PowerPoster techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,687

    Re: Can't Loop Through Items in a Collection

    Just for fun, change this:
    builder.Append(item & vbCrLf)
    to this:
    builder.Append(item & " // ")
    See if you're still only getting the first window... also check to see if you actually get the "//" to show...

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  13. #13

    Thread Starter
    New Member
    Join Date
    Apr 2010
    Posts
    12

    Re: Can't Loop Through Items in a Collection

    Quote Originally Posted by techgnome View Post
    Just for fun, change this:
    builder.Append(item & vbCrLf)
    to this:
    builder.Append(item & " // ")
    See if you're still only getting the first window... also check to see if you actually get the "//" to show...

    -tg
    The first window still shows. The "//" don't show. The output doesn't look any different from what I had before.

  14. #14
    PowerPoster techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,687

    Re: Can't Loop Through Items in a Collection

    That tells me a lot then....

    This is line is actually the source of the problem:
    GetWindowText(hwnd, text, Int16.MaxValue)
    When APIs return strings, they are NULL-terminated... so as you are stringing along your strings when adding them to string builder, when the NULL is hit on the end of the first string, that effectively ends the string.... so what gets appended after that "doesn't exist" ...

    You can do one of two things.... 1) Strip the null character before adding it to your collection of string... or 2) strip the null character from the string before passing it to the string builder.

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  15. #15

    Thread Starter
    New Member
    Join Date
    Apr 2010
    Posts
    12

    Re: Can't Loop Through Items in a Collection

    Quote Originally Posted by techgnome View Post
    That tells me a lot then....

    This is line is actually the source of the problem:
    GetWindowText(hwnd, text, Int16.MaxValue)
    When APIs return strings, they are NULL-terminated... so as you are stringing along your strings when adding them to string builder, when the NULL is hit on the end of the first string, that effectively ends the string.... so what gets appended after that "doesn't exist" ...

    You can do one of two things.... 1) Strip the null character before adding it to your collection of string... or 2) strip the null character from the string before passing it to the string builder.

    -tg
    Spot on!

    So, I added item = Replace(item, Chr(0), "") before builder.Append(item) and now it works!

    Much appreciated. Thanks!

  16. #16
    PowerPoster techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,687

    Re: Can't Loop Through Items in a Collection

    Excellent! Sorry for the run around initially.

    Don't forget to mark the thread resolved (under Thread Tools at the top).

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width