Solved

Window Enumeration

Posted on 2001-06-15
18
215 Views
Last Modified: 2009-07-29
The question suggests a slightly less complex system than is required... Basically I want to enumerate all open windows on the system, pick out the MSN Messenger Instant Message windows (probably just by checking if the caption ends in " - Instant Message"). Once I have the handles for these windows, I will then need to get the participants and the conversation (Participants in the "To: " text box near the top of the window, and the conversation is in a rich text box I'm guessing... although it's probably not.). It would then put the conversation text in a file (which would be just for that conversation... i can handle that part of it myself really...)

I know it's a lot to ask for 200 points... but it's part of a system logging program that I'm writing to make logging conversations, etc. easier.

Has anybody got any ideas?
0
Comment
Question by:j3877
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 9
  • 8
18 Comments
 
LVL 6

Expert Comment

by:JonFish85
ID: 6197017
try this code:

'------------ In module -------------'
Option Explicit

Declare Function EnumWindows Lib "user32" (ByVal lpEnumFunc As Long, ByVal lParam As Long) As Boolean
Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hwnd As Long) As Long
Public Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Public Declare Function SetWindowText Lib "user32" Alias "SetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String) As Long
Public Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long

Public Function EnumWindowsProc(ByVal hwnd As Long, ByVal lParam As Long) As Boolean
Dim sSave As String, Ret As Long
Dim ClsName As String

    Ret = GetWindowTextLength(hwnd)
    sSave = Space(Ret)
    GetWindowText hwnd, sSave, Ret + 1
    If (sSave <> "") And (InStr(sSave, "Instant Message")) Then
      sSave = Left(sSave, InStr(sSave, "- Instant Message") - 2)
      ClsName = String(255, 0)
      Ret = GetClassName(hwnd, ClsName, Len(ClsName))
      ClsName = Left(ClsName, Ret)
      If UCase(ClsName) = "IMWINDOWCLASS" Then
        '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        '%%% Write to file %%%%%%%%%%%
        '%%% Chatting with = sSave %%%
        '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      End If
    End If
    EnumWindowsProc = True
End Function



'------------- In form code --------------'
Private Sub Command1_Click()
  'Find MSN windows
  EnumWindows AddressOf EnumWindowsProc, ByVal 0&
End Sub



hope that helps!
0
 
LVL 1

Author Comment

by:j3877
ID: 6197033
Thanks - it's good, well laid out code... but I need to save the e-mail addresses of the participants, as well as the text for that chat...

Keep the ideas coming.
0
 
LVL 6

Expert Comment

by:JonFish85
ID: 6197156
Microsoft seems to not want to let other programs access its text in it's windows, so I devised a workaround. Replace the module's code with this (leave the form code the same)

Option Explicit

Declare Function EnumWindows Lib "user32" (ByVal lpEnumFunc As Long, ByVal lParam As Long) As Boolean
Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hwnd As Long) As Long
Public Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Public Declare Function SetWindowText Lib "user32" Alias "SetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String) As Long
Public Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Public Declare Function GetDlgItemText Lib "user32" Alias "GetDlgItemTextA" (ByVal hDlg As Long, ByVal nIDDlgItem As Long, ByVal lpString As String, ByVal nMaxCount As Long) As Long
Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Public Const WM_COPY = &H301

Public Function EnumWindowsProc(ByVal hwnd As Long, ByVal lParam As Long) As Boolean
Dim sSave As String, Ret As Long
Dim ClsName As String
Dim hEmail As Long
Dim sEmail As String

    Ret = GetWindowTextLength(hwnd)
    sSave = Space(Ret)
    GetWindowText hwnd, sSave, Ret + 1
    If (sSave <> "") And (InStr(sSave, "Instant Message")) Then
      sSave = Left(sSave, InStr(sSave, "- Instant Message") - 2)
      ClsName = String(255, 0)
      Ret = GetClassName(hwnd, ClsName, Len(ClsName))
      ClsName = Left(ClsName, Ret)
      If UCase(ClsName) = "IMWINDOWCLASS" Then
        hEmail = FindWindowEx(hwnd, 0, "edit", vbNullString)
        SendMessage hEmail, WM_COPY, 0, 0
        sEmail = sSave & " " & Clipboard.GetText
        '% sEmail = "Name <email@address.com>"
        '%save it to a file here
      End If
    End If
    EnumWindowsProc = True
End Function


hope that works!
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 1

Author Comment

by:j3877
ID: 6197176
Ok once again... good code.. but I can't see the text for capturing the conversation text... am I missing something? :s
0
 
LVL 6

Expert Comment

by:JonFish85
ID: 6197184
Im working on it! This is a bit more tricky :-D
0
 
LVL 1

Author Comment

by:j3877
ID: 6197192
Thanks. I appreciate your speedy work so far :-D
0
 
LVL 1

Author Comment

by:j3877
ID: 6197199
I remember seeing it as a feature in SubSeven (capturing text from an msn chat window)...
0
 
LVL 5

Expert Comment

by:dgorin
ID: 6197303
This link shows how to enumerate windows and child windows.

http://www.mvps.org/vbnet/index.html?code/enums/enumwindowsdemo.htm
0
 
LVL 6

Expert Comment

by:JonFish85
ID: 6197453
dgorin, the problem Im having is that the MSN child window's dont respond to WM_GETTEXT. Therefore I am using the clipboard as a go-between kinda...
0
 
LVL 6

Expert Comment

by:JonFish85
ID: 6197516
here's some ugliness I put together:

Option Explicit

Declare Function EnumWindows Lib "user32" (ByVal lpEnumFunc As Long, ByVal lParam As Long) As Boolean
Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hwnd As Long) As Long
Public Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Public Declare Function SetWindowText Lib "user32" Alias "SetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String) As Long
Public Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Public Declare Function SetFocusAPI Lib "user32" Alias "SetFocus" (ByVal hwnd As Long) As Long
Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Public Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
Public Type RECT
        Left As Long
        Top As Long
        Right As Long
        Bottom As Long
End Type
Public Const WM_COPY = &H301
Public Const WM_LBUTTONDOWN = &H201
Public Const WM_LBUTTONUP = &H202
Public Const WM_LBUTTONDBLCLK = &H203

Public Function EnumWindowsProc(ByVal hwnd As Long, ByVal lParam As Long) As Boolean
Dim sSave As String, Ret As Long
Dim ClsName As String, r As RECT
Dim hEmail As Long, hChat As String
Dim sEmail As String, AppTitle As String
Dim sChat As String

    Ret = GetWindowTextLength(hwnd)
    sSave = Space(Ret)
    GetWindowText hwnd, sSave, Ret + 1
    If (sSave <> "") And (InStr(sSave, "Instant Message")) Then
      sSave = Left(sSave, InStr(sSave, "- Instant Message") - 2)
      ClsName = String(255, 0)
      Ret = GetClassName(hwnd, ClsName, Len(ClsName))
      ClsName = Left(ClsName, Ret)
      If UCase(ClsName) = "IMWINDOWCLASS" Then
        AppTitle = sSave & " - Instant Message"
        hEmail = FindWindowEx(hwnd, 0, "edit", vbNullString)
        GetWindowRect hEmail, r
        AppActivate AppTitle, True
        SendMessage hEmail, WM_LBUTTONDOWN, 10, 10
        SendMessage hEmail, WM_LBUTTONUP, 10, 10
        SendKeys "{HOME} +{END}", True
        SendMessage hEmail, WM_COPY, 0, 0
        SendKeys "{HOME}", True
        sEmail = Clipboard.GetText
        hEmail = FindWindowEx(hwnd, 0, "RichEdit20W", vbNullString)
        GetWindowRect hEmail, r
        SendMessage hEmail, WM_LBUTTONDOWN, 10, 10
        SendMessage hEmail, WM_LBUTTONUP, 10, 10
        SendMessage hEmail, WM_COPY, 0, 0
        SendKeys "{HOME}", True
        sChat = Clipboard.GetText
        Form1.Print "Contact: " & sEmail & vbCrLf & "Chat: " & Left(sChat, 25) & "..." & vbCrLf & vbCrLf
      End If
    End If
    EnumWindowsProc = True
End Function




ahhhhhhhhhhhhhhhhhhhhhhhhhhhh
0
 
LVL 1

Author Comment

by:j3877
ID: 6197865
it doesn't work for me :(
It just outputs the e-mail address twice:(
0
 
LVL 6

Accepted Solution

by:
JonFish85 earned 220 total points
ID: 6198267
try changing this:

       SendMessage hEmail, WM_LBUTTONDOWN, 10, 10
       SendMessage hEmail, WM_LBUTTONUP, 10, 10
       SendMessage hEmail, WM_COPY, 0, 0
       SendKeys "{HOME}", True

to this:
       SendMessage hEmail, WM_LBUTTONDOWN, 10, 10
       SendMessage hEmail, WM_LBUTTONUP, 10, 10
       SendKeys "{END}", True
       SendMessage hEmail, WM_COPY, 0, 0
       SendKeys "{HOME}", True
0
 
LVL 6

Expert Comment

by:JonFish85
ID: 6198268
arghhhh and change the {END} to
+{END}

sorry bout all these posts!
0
 
LVL 1

Author Comment

by:j3877
ID: 6198270
also another problem: I will be talking while this occurs... isn't there a way of sending keys to the window without it being active?
0
 
LVL 6

Expert Comment

by:JonFish85
ID: 6198273
Im sure there is a way with sendmessage/wm_keydown/wm_keyup, and that was my first idea. However, I couldnt get it to work :-/ I'll work on it some more tonight. Id work on it during the day but I have 2 baseball games to play. Sorry this is taking so long!
0
 
LVL 1

Author Comment

by:j3877
ID: 6198277
It's okay... no huge rush:)
0
 
LVL 1

Author Comment

by:j3877
ID: 6198292
Okay I've tweaked your code just slightly (and upped the points) and got it working - it wasn't working when i updated it from the code you gave me (probably a problem with my update) so i changed it thus:

Public Function EnumWindowsProc(ByVal hwnd As Long, ByVal lParam As Long) As Boolean
    ClipboardContents = Clipboard.GetText
   
    Dim sSave As String, Ret As Long
    Dim ClsName As String, r As RECT
    Dim hEmail As Long, hChat As String
    Dim sEmail As String, AppTitle As String
    Dim sChat As String
   
    Ret = GetWindowTextLength(hwnd)
    sSave = Space(Ret)
    GetWindowText hwnd, sSave, Ret + 1
    If (sSave <> "") And (InStr(sSave, "Instant Message")) Then
        sSave = Left(sSave, InStr(sSave, "- Instant Message") - 2)
        ClsName = String(255, 0)
        Ret = GetClassName(hwnd, ClsName, Len(ClsName))
        ClsName = Left(ClsName, Ret)
        If UCase(ClsName) = "IMWINDOWCLASS" Then
            AppTitle = sSave & " - Instant Message"
            hEmail = FindWindowEx(hwnd, 0, "edit", vbNullString)
            GetWindowRect hEmail, r
            AppActivate AppTitle, True
            SendMessage hEmail, WM_LBUTTONDOWN, 10, 10
            SendMessage hEmail, WM_LBUTTONUP, 10, 10
            SendKeys "{HOME} +{END}", True
            SendMessage hEmail, WM_COPY, 0, 0
            SendKeys "{HOME}", True
            sEmail = Clipboard.GetText
            hEmail = FindWindowEx(hwnd, 0, "RichEdit20W", vbNullString)
            GetWindowRect hEmail, r
            SendMessage hEmail, WM_LBUTTONDOWN, 10, 10
            SendMessage hEmail, WM_LBUTTONUP, 10, 10
            SendKeys "{HOME} +{END}", True
            SendMessage hEmail, WM_COPY, 0, 0
            SendKeys "{HOME}", True
            SendKeys "{TAB}^C{END}{TAB}", True
            sChat = Clipboard.GetText
            LogConversation sEmail, sChat
        End If
    End If
    EnumWindowsProc = True
    Clipboard.SetText ClipboardContents
End Function

So it now doesn't erase the clipboard's text, and will return the carat to the message field.
Is there a way to return the focus to the window which was active at the start?
0
 
LVL 1

Author Comment

by:j3877
ID: 6198413
Okay I've done that - it now only saves text from the window that's currently being worked in every so often.
0

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

The debugging module of the VB 6 IDE can be accessed by way of the Debug menu item. That menu item can normally be found in the IDE's main menu line as shown in this picture.   There is also a companion Debug Toolbar that looks like the followin…
Article by: Martin
Here are a few simple, working, games that you can use as-is or as the basis for your own games. Tic-Tac-Toe This is one of the simplest of all games.   The game allows for a choice of who goes first and keeps track of the number of wins for…
As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…

740 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question