Get control handle of external application

Hello, I’m trying to update a label and press a button in an external (Xojo) App I created. This is for Windows. I was able to get the window handle with some help from a post resolved by Arnaud N. Below is that code. What I want to do is within that app I want to find the label that has a text of “USER NAME” and change it to say “GEORGE”, and I want to click the button with the caption of “REFRESHNAME”. Below my window handle code is some code I used in .NET to do this but I cannot figure it out in Xojo. Any help would be great, thanks.

—Xojo Find Window handle

Soft Declare Function FindWindowW Lib "user32.dll" (lpClassName As integer,lpWindowName As integer) as integer
Soft Declare Function GetWindow Lib "user32" (hWnd As integer,wCmd As integer) As integer
Soft Declare Function GetWindowTextW Lib "user32" (hWnd As integer,lpString As ptr,cch As integer) As integer

Dim ret As Integer
Dim mb as new MemoryBlock(255)

ret=FindWindowW(0,0)
While ret>0
  if GetWindowTextW(ret,mb,mb.size)>0 then
    lstCurrentScan.AddRow(mb.WString(0))
    lstWindowHandle.AddRow(ret.tostring)
    if mb.WString(0)="TWINS" then
      exit
    end if
  end if
  ret=GetWindow(ret,2)
Wend

—.NET code

Public Declare Function SendMessageSTRING Lib "user32.dll" Alias "SendMessageA" (ByVal hwnd As Int32, ByVal wMsg As Int32, ByVal wParam As Int32, ByVal lParam As String) As Int32
Public Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hWnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As IntPtr) As IntPtr
Public Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal hWnd1 As Int32, ByVal hWnd2 As Int32, ByVal lpsz1 As String, ByVal lpsz2 As String) As Int32
Public Const WM_SETTEXT = &HC
Public Const BM_CLICK = &HF5

Dim s as string = "GEORGE
Dim Handle As IntPtr = FindWindowEx(Hwnd, IntPtr.Zero, Nothing, "USER NAME")
Dim hWndButton As IntPtr = FindWindowEx(Hwnd, IntPtr.Zero, Nothing, "REFRESHNAME")

SendMessageSTRING(Handle, WM_SETTEXT, IntPtr.Zero, s)
SendMessage(hWndButton, BM_CLICK, 0&, 0&)

Untested translation:

  Declare Function SendMessageW Lib "User32" (HWND As Integer, Msg As Integer, WParam As Ptr, LParam As WString) As Integer
  Declare Function FindWindowExW Lib "User32" (Parent As Integer, ChildAfter As Integer, Classname As WString, WindowName As WString) As Integer
  Const WM_SETTEXT = &hC
  Const BM_CLICK = &hF5
  
  Dim Handle As Integer = FindWindowExW(Hwnd, 0, Nil, "USER NAME")
  Dim hWndButton As Integer = FindWindowExW(Hwnd, 0, Nil, "REFRESHNAME")
  
  Call SendMessageW(Handle, WM_SETTEXT, Nil, "GEORGE")
  Call SendMessageW(hWndButton, BM_CLICK, Nil, Nil)
1 Like

maybe also a solution
https://documentation.xojo.com/api/networking/ipcsocket.html

Worked like a charm Andrew. Thanks!

Andrew,
After looking into this more I realized that the button click (BM_CLICK) does not work/do anything. I was able to send the message to the label and change the label name but I am unable to click the button on sendmessage. Is the const wrong or something? Thanks for any help you can provide.

I’m able to change the caption on the button but not click it so I know I have the right handle.

You might try sending WM_LBUTTONDOWN followed by WM_LBUTTONUP instead of BK_CLICK:

Const WM_LBUTTONUP = &H202
Const WM_LBUTTONDOWN = &H201

Call SendMessageW(hWndButton, WM_LBUTTONDOWN, Nil, Nil)
Call SendMessageW(hWndButton, WM_LBUTTONUP, Nil, Nil)

Hah, I was literally just trying that, found a reference to it on another site where somebody suggested it because they said sometimes one works and the other doesn’t. It worked! Thanks for the quick reply!

1 Like

Happy to help.

The documentation says it might fail if the button is on an inactive dialog box.It goes on to suggest using SetActiveWindow, but it’s documentation makes it sound like it should only be used within the app that owns the window; maybe send a WM_ACTIVATE message (to the window, not the button) instead?

I seem to remember from my time working with the Win32 API using these functions that the WM messages were more reliable than BK_CLICK because many controls simply didn’t respond to BK_CLICK the same way, or at all, as they do with WM_LBUTTONDOWN and WM_LBUTTONUP, but I could be remembering that wrong. It’s been nearly 15 years since I had to do this regularly.

@JulianS would probably have some insight as the resident Win32 API guru.

Thanks. It seems like there’s some inconsistencies with it. I’ve a got a simple app that I created for testing that finds the button and clicks it. I have the same exact button type and name in a different app and it doesn’t click it. The one that doesn’t work is the same window type and title as the sample app. I’m also seeing that after having the button work 3 or 4 times it quits working. Definitely seems like an Active Window thing like you mentioned. Below is my code. I have 2 buttons, one with the caption “USER NAME” which I use to update the user name. (Tried using a label but it seems that does not update correctly in Xojo Windows (saw a post about it). My other button is captioned “REFRESHNAME” and is the one that needs to be clicked. It works for the sample app but not my other app that I need it to.

Soft Declare Sub ShowWindow Lib “User32” (wnd As Integer, nCmdShow As Integer)
Soft Declare Function SetForegroundWindow Lib “User32” (hWnd As Integer) As Integer
Declare Function SendMessageW Lib “User32” (HWND As Integer, Msg As Integer, WParam As Ptr, LParam As WString) As Integer
Declare Function FindWindowExW Lib “User32” (Parent As Integer, ChildAfter As Integer, Classname As WString, WindowName As WString) As Integer
Const WM_SETTEXT = &hC
Const BM_CLICK = &hF5
Const WM_LBUTTONDOWN = &H201
Const WM_LBUTTONUP = &H202

Handle = FindWindowExW(ret, 0, Nil, “USER NAME”)
hWndButton = FindWindowExW(ret, 0, Nil, “REFRESHNAME”)

Call SendMessageW(Handle, WM_SETTEXT, Nil, “FOUND”)

Call SendMessageW(hwndButton, WM_LBUTTONDOWN, Nil, Nil)
Call SendMessageW(hwndButton, WM_LBUTTONUP, Nil, Nil)
ShowWindow(ret,9)
Call SetForeGroundWindow(ret)