Find window by class name - winapi

I want to close a certain window.
Spy++ tells me that the window is of class name "ad_win#2":
However, when I use FindWindow like that...
Public Declare Function FindWindow Lib "USER32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Dim lRet&
lRet = FindWindow("ad_win#2", vbNullString)
.... lRet is 0, meaning that it didn't find any window.
What am I doing wrong?
Thank you!

It works when I add a ChrW(10) to the name like this:
Dim lRet&
lRet = FindWindow("ad_win#2" & ChrW(10), vbNullString)

Related

How to find a window by FindWindowW from the unicode window title text?

I have tried to use GetWindowTextW to extract the window title text successfully, and it is a unicode text. When I use FindWindowW to find the window, it failed and the returned Hwnd is 0.
The window with the unicode title:
The code on VB6 is below. the currentHwnd is the window Hwnd I captured already and it works well during my test:
Private Declare Function FindWindowW Lib "user32" (ByVal lpClassName As Long, ByVal lpWindowName As Long) As Long
Private Declare Function GetWindowTextW Lib "user32" (ByVal hWnd As Long, ByVal lpString As Long, ByVal cch As Long) As Long
Private Declare Function GetWindowTextLengthW Lib "user32" (ByVal hWnd As Long) As Long
Private Sub cmdOK_Click()
Dim titleString As String
dim newHwnd as Long
dim Class as string
Class = Space(500)
GetClassName currentHwnd, Class, Len(Class)
titleString = String$(256, 0)
GetWindowTextW currentHwnd, StrPtr(titleString), GetWindowTextLengthW(currentHwnd)
newHwnd = FindWindowW(StrPtr(Class), StrPtr(titleString))
End Sub

FindWindow() not working

I am writing a Little VBA Programm that Needs to wait until a specific windows is open. I want to do this using FindFindow form the user32.dll but i cant get it run. Weird Thing is that even if i set the 2 Parameters of the function to Null, i still get a negative return, although in that case all windows should match. Basically i dont get a result different from 0 for hwnd Independent of how i call FindWindow. I searched Stack OPverflow and i also Googled the Problem but i cant find what i am doing wrong. Any help is appreciated.
Declare Function FindWindow Lib "user32" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Sub Main
Dim hwnd As Long
hwnd = FindWindow(vbNullString, vbNullString)
If (hwnd = 0) Then MsgBox ("failure")
End Sub
The Solutions to similar Problems like How to use FindWindow to find a visible or invisible window with a partial name in VBA dont seem to work either.
The problem is that vbNullString is a length 0 string, the same as "". When that is marshalled to the unmanaged code a non-null pointer to a null-terminated array of characters is passed. Because the length is 0 then a pointer to a null-terminator is passed. That's different from NULL which is the null pointer.
I'm far from a VBA expert, but I think the solution is like so:
Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByRef lpClassName As Any, ByRef lpWindowName As Any) As Long
If you want to call this passing NULL for both arguments do so like this:
window = FindWindow(ByVal 0&, ByVal 0&)
Alternatively, if you want to pass a string value do it like this:
window = FindWindow(ByVal 0&, ByVal "Untitled - Notepad")

GetWindowText does not work

I'm trying to retrieve the text from an EDIT control using GetWindowText and GetWindowTextLength. The application retrieves the text from the window under the cursor and it works on all windows with a caption or text with the exception of the EDIT control. The EDIT control is the result window on the Windows XP Calculator, calc.exe.
Dim S As String
Dim L As Long
L = GetWindowTextLength(handle) + 1
Receiving string = GetWindowText(handle, S, L)
EDIT:
According to SPY++ the Edit class control does not receive the EM_GETSELTEXT or the WM_GETTEXT message.The code below retrieves the text from the Edit class control on the Windows XP calc.exe calculator every time that I press a button on my UI. It is not the method that I would have preferred to use, however, it accomplishes my task.
Const EM_SETSEL = &HB1
Const ES_READONLY = &H800
Const WM_COPY = &H301
Const EM_GETSELTEXT = &H43E
Const WM_GETTEXTLENGTH = &HE
Const WM_SETFOCUS As Long = &H7
Dim L As Long
L = SendMessage(EditHwnd, WM_GETTEXTLENGTH, 0&, 0)
SendMessage EditHwnd, WM_SETFOCUS, 0&, 0
SendMessage EditHwnd, EM_SETSEL, 0&, L
SendMessage EditHwnd, ES_READONLY, 0&, 0 ' read only = false
Clipboard.Clear
SendMessage EditHwnd, WM_COPY, 0&, 0
SendMessage EditHwnd, ES_READONLY, 1&, 0 ' read only = true
Receiving string = Clipboard.GetText
Clipboard.Clear
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hwnd As Long) As Long
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Function GetText(handle As Long) As String
Dim S As String, L As Integer, cch As Long
L = GetWindowTextLength(handle) + 1
S = String(L, 0)
GetText = Mid(S, 1, GetWindowText(handle, S, L))
End Function
Private Sub Form_Load()
Dim hw As Long
hw = Me.hwnd
MsgBox GetText(hw)
End Sub
But it will not work with controls like EDIT, as it is written in help. ;( In order to get the text of the child window (control), try to get a list of all windows using API EnumWindows/EnumThreadWindows/GetWindowThreadProcessId, to find the desired control.
What is the name of the class to EDIT You need? What is its width and height? I could write code specifically for the search for this control.
this code works fine in Windows XP (virtual machine)
Private Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" _
(ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As Any, ByVal lpsz2 As Any) As Long
Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" _
(ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByRef lParam As Any) As Long
Private Declare Function AttachThreadInput Lib "user32.dll" _
(ByVal idAttach As Long, ByVal idAttachTo As Long, ByVal fAttach As Long) As Long
Private Const WM_GETTEXT As Long = &HD&
Private Const WM_GETTEXTLENGTH As Long = &HE&
Function WindowText(ByVal hWnd As Long) As String
Dim ret As Long
ret = SendMessage(hWnd, WM_GETTEXTLENGTH, 0, ByVal 0&)
WindowText = String(ret, 0)
ret = SendMessage(hWnd, WM_GETTEXT, ret + 1, ByVal WindowText)
End Function
Private Sub Command1_Click()
Dim hCalc As Long, hEdit As Long
hCalc = FindWindow("SciCalc", vbNullString)
hEdit = FindWindowEx(hCalc, 0&, "Edit", vbNullString)
MsgBox WindowText(hEdit)
End Sub

Setting the name of a file in the Windows Save File dialog

Below is a an updated example where through Excel (vba), the sub opens Notepad, adds text and then prompts for a save as file name. It works except the passing of the file name from the vba code to Windows Save File dialog.
Option Explicit
Private Declare Function AllowSetForegroundWindow Lib "user32.dll" (ByVal dwProcessId As Long) As Long
Private Declare Function BringWindowToTop Lib "user32" (ByVal lngHWnd As Long) As Long
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpszClass As String, ByVal lpszTitle As String) As Long
Private Declare Function LockSetForegroundWindow Lib "user32.dll" (ByVal uLockCode As Long) As Long
Private Declare Function SendMessageString Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As String) As Long
Private Declare Function SetForegroundWindow Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Sub keybd_event Lib "user32.dll" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Long, ByVal dwExtraInfo As Long)
Private Const WM_SETTEXT As Long = &HC
Private Const LSFW_LOCK = 1
Private Const VK_CONTROL = &H11 '0x11
Private Const VK_S = &H53 '0x53
Sub WriteToNotepad()
Dim hwndNotepad&, hwndTextbox&, hwndSaveAs&, hwndSaveLocation, hwndFileName&, Retval
ResumeHere:
' Start "Notepad"
Retval = Shell("C:\Windows\System32\NotePad.exe", 4)
' Identify handle for "Notepad" window
hwndNotepad = FindWindowEx(0, 0, "Notepad", vbNullString)
hwndTextbox = FindWindowEx(hwndSaveAs, 0, "Edit", vbNullString)
' Write message
SendMessageString hwndTextbox, WM_SETTEXT, 0, "My message goes here"
' Lock the window for futher input
BringWindowToTop (hwndNotepad)
AllowSetForegroundWindow (hwndNotepad)
SetForegroundWindow (hwndNotepad)
LockSetForegroundWindow (LSFW_LOCK)
' Show Save As dialog box
'Press Ctrl key down, but don't release
keybd_event VK_CONTROL, 0, 0, 0
'Press the letter "S" then release
keybd_event VK_S, 0, 0, 0
keybd_event VK_S, 0, 2, 0
'Release the Alt key
keybd_event VK_CONTROL, 0, 2, 0
' Find SaveAs window before continuing
hwndSaveAs = FindWindowEx(0, 0, "#32770", vbNullString)
hwndFileName = FindWindowEx(hwndSaveAs, 0, "Edit", vbNullString)
' Write file name
SendMessageString hwndFileName, WM_SETTEXT, 0, "Testing file.txt"
End Sub
Well, you certainly don't do it by synthesizing keystrokes. The correct way of pre-filling the file name field in the Save (or Open) dialog is to put the desired string in the lpstrFile member of the OPENFILENAME structure that you pass to the GetSaveFileName function.
When the dialog is closed by the user, that field will be updated with the file name and path that was selected.

sendmessage not working for jetaudio in vb6

i am trying to implement the Jetaudio API in vb6...
i have taken the values of the constants from the API SDK..
Private Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" ( _
ByVal lpClassName As String, _
ByVal lpWindowName As String) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function RegisterWindowMessage _
Lib "user32" Alias "RegisterWindowMessageA" _
(ByVal lpString As String) As Long
Public Const WM_APP As Long = &H8000
Public Const MyMSG As Long = WM_APP + 740
Public Function GetJetAudioSong()
Dim v As Long
Dim JAhwnd As Long
Dim lngMyMsg As Long
lngMyMsg = RegisterWindowMessage(MyMSG)
JAhwnd = FindWindow("COWON Jet-Audio Remocon Class", "Jet-Audio Remote Control")
v = SendMessage(JAhwnd, lngMyMsg, 0, 995)
MsgBox v
End Function
Now, FindWindow() is working cause JAhwnd is set with a value...
its just the sendmessage() that doesn't seem to be working...
the code is suppose to msgbox the version number for the running Jet Audio instance.
i've been at it for days now and i have no way of making sure weather this error is a VB thing or not... i am taking Jet Audio's SDK's word that the values of the const are correct...
the value of v is always 0 where it should be 6 on my system.
what am i doing wrong?
Don't call RegisterWindowMessage, MyMSG is message number that you should send to the Jet-Audio window.
Private Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" ( _
ByVal lpClassName As String, _
ByVal lpWindowName As String) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Public Const WM_APP As Long = &H8000
Public Const MyMSG As Long = WM_APP + 740
Public Function GetJetAudioSong()
Dim v As Long
Dim JAhwnd As Long
Dim lngMyMsg As Long
JAhwnd = FindWindow("COWON Jet-Audio Remocon Class", "Jet-Audio Remote Control")
v = SendMessage(JAhwnd, MyMSG, 0, 995)
MsgBox v
End Function
What Windows Version?
SendMessage and SendKeys no longer works with VB6 code starting at Windows Vista and above.
Do a Google search for it.
I know this is 2 years too late. Please use this as a future reference for anyone reading this in the future.
The fix for your issue is this:
'[ Use 'ByVal' for your lParam to make sure you are passing the actual value not the Reference
v = SendMessage(JAhwnd, lngMyMsg, 0, ByVal 995)
'[ Or you could perform PostMessage(..) and not use ByVal
v = PostMessage(JAhwnd, lngMyMsg, 0, 995)
Also, i HIGHLY recommend against anyone using SendKeys. API is the correct method to ensure you are sending message to the correct hWnd. I would suggest using SendKeys only if in desperation; it can happen.

Resources